草庐IT

android - 是否可以@Inject 成员(通过@Provides 提供),包含来自基本 Activity 的 Activity 上下文

coder 2023-12-18 原文

好的。让我试着分解一下这种情况,因为我认为标题可能有点不清楚。在继续之前,我会尽可能多地说,我已经尝试将此应用程序的基本结构基于 official dagger examples .

基本上我想做的是能够注入(inject)一个 LocationClient进入我的 SplashActivity,以便在 App 打开后立即建立连接(通过 LocationClient.connect())。

现在,很明显,LocationClient 不能通过任何类型的默认构造函数注入(inject)(它需要一些非常具体的东西(上下文和一些回调)。所以,我创建了一个 @Provides 在我的 ActivityModule 中:

@Provides
@Singleton
LocationClient providesLocationClient(@ForApplication Context context, LocationService service) {
  return new LocationClient(context, service, service);
}

LocationService 是我创建的类,用于实现 LocationClient 所需的回调。我还在我的 ActivityModule 中通过 @Provides 提供:

@Provides
@Singleton
LocationService providesLocationService(@ForActivity Context context, Logger logger) {
    return new LocationService(context, logger);
}

我会在最后提供所有相关文件的完整代码,以供引用。

所以,我想@Inject一个LocationClient到我的SplashActivity。但是,当我这样做时,出现以下错误:

No injectable members on com.google.android.gms.location.LocationClient. Do you want to add an injectable constructor? required by class m.myapp.android.storemode.presentation.activity.SplashActivity

我发现只有两种方法可以避免此错误,但都不能满足我的需要。我也可以

  1. LocationClient 的注入(inject)移动到 Fragment 上。这不好,因为此时进入应用程序的流程已经太迟了。我希望此时能够开始调用 LocationClient,这需要建立连接。

  2. @Provides 中删除对 LocationService 的 Activity Context 的引用,并将 @Provides 中移出ActivityModuleAndroidModule。这也不好,因为我需要 Activity Context 来完成回调中的一些事情(如 Google 示例中所示,用于设置新的位置服务。

所以,这就是我陷入的困境。我希望这看起来有些道理。我很难解释它,因为它太分散了。下面是我的 ActivityModule、我的 AndroidModule、我的应用程序文件和我的 BaseActivity 的代码:

Activity 模块

@Module(
    injects = {MainActivity.class,
               SplashActivity.class,
               HomeFragment.class,
               StoreLocatorFragment.class,
               BrowseProductsFragment.class,
               BrowseProductCategoriesFragment.class},
    includes = {NetworkImageModule.class, ApiModule.class, WatchListModule.class},
    complete = false
)
public class ActivityModule {

    private final BaseActivity mActivity;

    public ActivityModule(BaseActivity activity) {
        this.mActivity = activity;
    }

    /**
     * Allow the mActivity context to be injected but require that it be annotated with {@link
     * ForActivity @ForActivity} to explicitly differentiate it from application context.
     */
    @Provides
    @Singleton
    @ForActivity
    Context provideActivityContext() {
        return mActivity;
    }

    @Provides
    @Singleton
    KeyboardHider provideKeyboardHider(InputMethodManager imm) {
        return new KeyboardHider(imm);
    }

    @Provides
    ProgressDialog providesProgressDialog() {
        return new ProgressDialog(mActivity);
    }

    @Provides
    @Singleton
    LocationService providesLocationService(@ForActivity Context context, Logger logger) {
        return new LocationService(context, logger);
    }

    @Provides
    @Singleton
    LocationClient providesLocationClient(@ForApplication Context context, LocationService service) {
        return new LocationClient(context, service, service);
    }

    @Provides
    @Singleton
    PIVenueIdService providesPiVenueIdService(LocationClient locationClient) {
        return new PIVenueIdService(locationClient);
    }

}

安卓模块

@Module(library = true)
public class AndroidModule {

    /**
     * SharedPreferences name
     */
    public static final String PREFERENCE_NAME = AndroidModule.class
            .getPackage()
            .getName() +
            "Preferences";

    private final StoreModeApplication mApplication;

    //Only created for testing
    public AndroidModule() {
        mApplication = null;
    }

    public AndroidModule(StoreModeApplication application) {
        mApplication = checkNotNull(application);
    }

    /**
     * Allow the application context to be injected but require that it be annotated with {@link
     * ForApplication @Annotation} to explicitly differentiate it from an activity context.
     */
    @Provides
    @Singleton
    @ForApplication
    Context provideApplicationContext() {
        return mApplication;
    }

    @Provides
    @Singleton
    SharedPreferences provideSharedPreferences() {
        return mApplication.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
    }

    @Provides
    @Singleton
    RequestQueue provideRequestQueue() {
        return Volley.newRequestQueue(mApplication);
    }

    @Provides
    @Singleton
    ActivityManager provideActivityManager() {
        return (ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
    }

    @Provides
    @Singleton
    LocationManager provideLocationManager() {
        return (LocationManager) mApplication.getSystemService(Context.LOCATION_SERVICE);
    }

    @Provides
    @Singleton
    Logger provideLoggingService() {
        return new LogCatLogger();
    }

    @Provides
    @Singleton
    Gson provideGson() {
        return new Gson();
    }

    @Provides
    @Singleton
    InputMethodManager provideInputMethodManager() {
        return (InputMethodManager) mApplication.getSystemService(Context.INPUT_METHOD_SERVICE);
    }

}

申请文件

public class StoreModeApplication extends Application {

    private static StoreModeApplication sInstance;

    private ObjectGraph mGraph;


    /**
     * Only use this for easy access to inject function
     */
    public static StoreModeApplication getInstance() {
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // Setup debugging for butterknife
        Views.setDebug(BuildConfig.DEBUG);

        // Create ability to get instance
        sInstance = this;

        // Setup DI
        mGraph = ObjectGraph.create(getModules().toArray());


    }


    /**
     * Used for injecting dependencies
     *
     * @param object object that needs dependencies injected
     */
    public void inject(Object object) {
        mGraph.inject(object);
    }

    /**
     * Gets mGraph.
     *
     * @return Value of mGraph.
     */
    public ObjectGraph getApplicationGraph() {
        return mGraph;
    }

    /**
     * Creates a list containing all the modules required for dagger
     */
    private List<Object> getModules() {
        return Arrays.asList(
                new AndroidModule(this),
                new ActivityObjectMapperModule(),
                new NetworkImageModule()
        );
    }

基础 Activity

public abstract class BaseActivity extends Activity {

    private ObjectGraph mActivityGraph;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StoreModeApplication storeModeApplication = StoreModeApplication.getInstance();
        mActivityGraph = storeModeApplication.getApplicationGraph()
                .plus(
                        getModules().toArray()
                );

        mActivityGraph.inject(this);
    }

    @Override
    protected void onDestroy() {
        // Eagerly clear the reference to the activity graph to allow it to be garbage collected as
        // soon as possible.
        mActivityGraph = null;
        super.onDestroy();
    }

    protected List<Object> getModules() {
        return Arrays.asList(
                new ActivityModule(this),
                new StoreLocatorFragmentModule(),
                new WatchListModule()
        );
    }


    /**
     * Inject the supplied {@code object} using the activity-specific graph.
     */
    public void inject(Object object) {
        mActivityGraph.inject(object);
    }

最佳答案

我知道这是一个老问题,但你记得用 @Inject 注释 LocationService 的构造函数吗?

此外,LocationService 所需的 Logger 可能不明确,您可能还需要 provideLogger 以使 Dagger 能够找到该依赖项。

据我所知,唯一可能的错误来源。

关于android - 是否可以@Inject 成员(通过@Provides 提供),包含来自基本 Activity 的 Activity 上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18729322/

有关android - 是否可以@Inject 成员(通过@Provides 提供),包含来自基本 Activity 的 Activity 上下文的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  6. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  7. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  8. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  9. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  10. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

随机推荐