【问题标题】:Dagger2 Optimal way to inject dependencies from two different classesDagger2 从两个不同类注入依赖项的最佳方法
【发布时间】:2017-12-06 13:26:49
【问题描述】:

在搜索并尝试了太多事情之后,我陷入了一些看似简单的问题。 下面是我负责注入改造的模块。

@Module
public class NetworkingModule
{
    @Provides
    public Retrofit providesRetrofit()
    {
        Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
        Retrofit retrofit = new Retrofit.Builder()
                                        .baseUrl(Constants.BASE_URL)
                                        .addConverterFactory(GsonConverterFactory.create(gson))
                                        .build();

        return retrofit;
    }


}

我的网络组件

@Component( modules = NetworkingModule.class)
public interface NetworkingComponent {
    void inject(DashboardPresenterImpl target);

    void inject(PicksPresenterImpl picksPresenter);

    void inject(LoadsPresenterImpl loadsPresenter);

    void inject(ShippingPresenterImpl shippingPresenter);

    void inject(GeneralFilePresenterImpl generalFilePresenter);
}

具有构造函数注入的实用程序类。请注意这个类也有 AppPreferences 的注入。

public class AppUtils {
    private Context context;

    @Inject
    AppPreferences preferences;

    @Inject
    public AppUtils(@ActivityContext Context context)
    {
        this.context = context;

        /*ActivityComponent component = DaggerActivityComponent.builder()
                .activityModule(new ActivityModule((Activity) context))
                .build();
        component.inject(this);*/
    }
}

现在在我的代码中我想实现这个

Class MyPresenterImpl{
@Inject
    Retrofit retrofit;

    @Inject
    AppUtils appUtils;
}

请提出一种优化的好方法来实现上述目标。

编辑

添加 AppPreference.java

public class AppPreferences {
    @Inject
    SharedPreferences sharedPreferences;

    private SharedPreferences.Editor editor;

    @Inject
    public AppPreferences(@ActivityContext Context context)
    {
        ApplicationComponent component = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule((Application) context.getApplicationContext()))
                .build();
        component.inject(this);

        editor = sharedPreferences.edit();
    }

    public void putString(String key, String value)
    {
        editor.putString(key, value).commit();
    }

    public String getString(String key)
    {
        return sharedPreferences.getString(key, null);
    }

}

【问题讨论】:

    标签: android dependency-injection dagger-2


    【解决方案1】:

    请决定是使用字段注入还是构造函数注入,希望选择构造函数注入

    public class AppUtils {
      private Context context;
    
      @Inject // field injection?
      AppPreferences preferences;
    
      @Inject // constructor injection?
      public AppUtils(@ActivityContext Context context)
      {
        // ...
      }
    }
    

    如果您使用构造函数注入,Dagger 不会注入您的字段,之后您也不应该自己调用它。您的组件实际上不应该包含所有这些方法来注入您的演示者等。

    如果你需要一些东西,把它放在构造函数中。

    public class AppUtils {
      private Context context;
      private AppPreferences preferences;
    
      @Inject // constructor injection!
      public AppUtils(@ActivityContext Context context, AppPreferences preferences)
      {
        // ...
      }
    }
    

    这同样适用于MyPresenterImpl。如果你依赖某些东西,把它放在构造函数中,用@Inject标记构造函数,Dagger会为你创建对象,并提供所有依赖项。

    您的组件应仅包含适用于 Android 框架类型(Activity、Fragments 等)的 .inject(..) 方法,不得包含其他任何内容。

    我最近也和some general concepts写了一篇关于Dagger使用的文章。

    【讨论】:

    • 感谢您提供简单解释的好答案,但我的主要问题仍未得到解答,即Class MyPresenterImpl{ @Inject Retrofit retrofit; @Inject AppUtils appUtils; } Please suggest an optimize and good way to achieve the above. 现在您可以看到 NetworkModule 提供了 Retrofit,因为我在 AppUtils 中使用构造函数注入。如何在不为 MyPresenterImpl 创建单独组件的情况下注入两者。谢谢,我会阅读您分享的博客。
    • Your components should only contain .inject(..) method for Android framework types (Activities, Fragments, ...) and nothing else. 那么如何注入非框架类型呢?
    • 非框架类型应该由某些模块提供,所以只有构造函数注入(不需要调用inject())
    • @eCDroid 正如所指出的,您应该只使用构造函数注入。将每个依赖项放入构造函数中,然后完成。
    • 刚读完你的博客,很有帮助,是的,匕首一开始可能会很混乱,当你觉得你开始掌握它时,这只是一个开始。
    【解决方案2】:

    我的建议: 创建上下文模块:

    @Module
    public class ContextModule
    {
        Context context;
    
        public ContextModule(Context context) {
            this.context = context;
        }
    
        @Provides
        @AppScope
        Context context() {
            return context;
        }
    }
    

    创建 SharedPreferences 模块

    @Module
    public class SharedPreferencesModule
    {
    
        @Provides
        @AppScope
        AppSharedPreferences provideAppSharedPreferences(Context context) {
            return new AppSharedPreferences(context.getSharedPreferences("App",Context.MODE_PRIVATE));
        }
    }
    

    如果需要,您可以创建更多模块(例如 AppUtils)

    不要为网络创建单独的组件,而是为您的应用创建一个

    @Component( modules = {ContextModule.class, NetworkingModule.class, SharedPreferencesModule})
    public interface AppComponent {...
    

    【讨论】:

    • 感谢您的回答,我非常感谢,但这样任何想要构建 AppComponent 的类都必须在构建 DaggerAppComponent 时为 ContextModule、NetworkingModule 和 SharedPreferences 提供一个实例。我认为这不是最佳方式。
    • @eCDroid 我的建议和常见做法是在 Application 类中存储和公开一个 AppComponent 实例。由于您始终可以从任何上下文 (Context.getApplicationContext()) 获取应用程序对象,因此您可以轻松访问此组件。
    猜你喜欢
    • 2019-02-25
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    相关资源
    最近更新 更多