【问题标题】:Dagger retrofit cannot be provided无法提供匕首改装
【发布时间】:2018-08-18 21:27:21
【问题描述】:

诚然,Dagger 很难,我正在尝试注入 Retrofit。我注入了 Context 和 SharedPreferences,它运行良好。但 Retrofit 打破了这一切。 它识别 DaggerRetrofitComponent 类,但没有找到 DaggerAppComponent。

改造模块:

@Module
public class RetrofitModule {
    public static final String BASE_URL = "http://api.themoviedb.org/3/";
    @Provides
    HttpLoggingInterceptor getHttpLoggingInterceptor(){
        return new HttpLoggingInterceptor();

    }
    @Provides
    OkHttpClient getOkHttpClient(HttpLoggingInterceptor interceptor){
        return new OkHttpClient.Builder().addInterceptor(interceptor).build();
    }
    @Provides
    GsonConverterFactory getGsonConverterFactory(){
        return GsonConverterFactory.create();
    }
    @Provides
    Retrofit getRetrofit(GsonConverterFactory gsonConverterFactory, OkHttpClient client){
        return new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(gsonConverterFactory)
                .client(client).build();
    }
}

应用:

public class MyApplication extends Application {
    private static AppComponent appComponent;
    public static AppComponent getAppComponent(){
        return appComponent;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        appComponent=buildComponent();

    }


    protected AppComponent buildComponent(){
        if(BuildConfig.DEBUG){
            Timber.plant(new Timber.DebugTree());
        }

        return DaggerAppComponent.builder().sharedPreferenceModule(new SharedPreferenceModule()).contextModule(new ContextModule(this)).build();


    }
}

应用组件:

@Singleton
@Component(modules = {ContextModule.class, SharedPreferenceModule.class})
public interface AppComponent {
    void inject(MainActivity mainActivity);
}

改造组件:

@Singleton
@Component(modules = {RetrofitModule.class})
public interface RetrofitComponent {
    void injectRetrofit(Activity activity);
//
}

主活动:

public class MainActivity extends AppCompatActivity {
    @Inject
    Context context;
    @Inject
    SharedPreferences sharedPreferences;
    @Inject
    Retrofit retrofit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerRetrofitComponent.builder().retrofitModule(new RetrofitModule()).build().injectRetrofit(this);
        MyApplication.getAppComponent().inject(this);


    }
}

【问题讨论】:

    标签: android dependency-injection retrofit2 dagger-2


    【解决方案1】:

    删除这个类:

    //@Singleton
    //@Component(modules = {RetrofitModule.class})
    //public interface RetrofitComponent {
    //    void injectRetrofit(Activity activity);
    //
    //}
    

    并修改AppComponent:

    @Singleton
    @Component(modules = {ContextModule.class, SharedPreferenceModule.class, RetrofitModule.class})
    public interface AppComponent {
        void inject(MainActivity mainActivity);
    }
    

    【讨论】:

    • 这可行,但我如何分离应用程序和活动级别的依赖关系
    • Retrofit 不是 Activity 级别的依赖,它被标记为@Singleton
    • 是的,我明白了。但是你能举一个关于活动级别依赖的例子吗(不一定要改造)。
    • @Bissisingh 您的活动演示者是活动范围依赖的示例。
    • @mt0s 但是我是否注入了演示者,例如,除了我可以将所有内容转储到应用程序级别这似乎不太好。
    【解决方案2】:

    我不确定你为什么要让 Retrofit 成为一个组件(你的应用组件中的一个模块应该足够了),那么你应该使用最后一个 Dagger 版本来处理控制器视图(活动和片段)的自动注入

    @Singleton
    @Component(modules = [ApplicationModule::class])
    interface ApplicationComponent : AndroidInjector<MyApplication>
    {
        override fun inject(application: MyApplication)
    
        @Component.Builder
        interface Builder
        {
            @BindsInstance
            fun application(application: MyApplication): Builder
    
            fun build(): ApplicationComponent
        }
    }
    

    __

    @Module(includes = [AndroidSupportInjectionModule::class,ActivityBuilderModule::class, NetworkModule::class])
    abstract class ApplicationModule
    {
        @Binds
        @Singleton
        abstract fun bindApplication(application: MyApplication): Application
    
        @Module
        companion object
        {
            @Provides
            @Singleton
            @ApplicationContext
            @JvmStatic
            fun provideApplicationContext(application: MyApplication): Context = application
        }
    }
    

    __

    @Module
    abstract class ActivityBuilderModule
    {
        @ContributesAndroidInjector(modules = [MainActivityModule::class])
        @ActivityScope
        abstract fun contributeMainActivity(): MainActivity
    
        //others activities there
    }
    
    @Module
    object NetworkModule
    {
        // For simplicity just retrofit provider, but all others network resources should be here of course
    
        @Provides
        @Singleton
        @JvmStatic
        fun provideRetrofit(rxJava2CallAdapterFactory: RxJava2CallAdapterFactory,
                            nullOrEmptyConverterFactory: Converter.Factory,
                            @ApplicationContext okHttpClient: OkHttpClient,
                            gsonConverterFactory: GsonConverterFactory): Retrofit =
            Retrofit.Builder()
                .addCallAdapterFactory(rxJava2CallAdapterFactory)
                .addConverterFactory(nullOrEmptyConverterFactory)
                .addConverterFactory(gsonConverterFactory)
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .build()
    }
    

    __

    class MyApplication : DaggerApplication()
    {
        private val applicationInjector = DaggerApplicationComponent.builder()
            .application(this)
            .build()
    
        public override fun applicationInjector() = applicationInjector
    }
    

    __

    然后从您的活动/片段中使它们从 DaggerActivity 或 DaggerFragment 继承,您应该能够开箱即用地进行注入

    你可以看看我的模板项目https://github.com/SamYStudiO/beaver它可能会有所帮助。

    ps : 抱歉都是 kotlin 但应该很容易转换为 java

    【讨论】:

    • Kotlin 不是问题,但我还没有研究过大多数像 JVMstatic 这样的注释。
    • 什么是ActivityBuilderModule?
    • 我添加了它(从应用程序组件创建活动子组件很有用),如果你错过了所有来自它的东西,请查看我的 github 链接
    • @JvmStatic 只是一个注解,告诉 java 它是一个静态方法,因为 kotlin 没有静态关键字
    • MainActivityModule?我似乎无法在 github repo 上找到它
    【解决方案3】:

    Dagger 2 不允许从多个组件注入依赖项。您应该考虑使用子组件。

    https://google.github.io/dagger/subcomponents.html

    UPD:我建议您创建从您的 AppComponent 派生的子组件,例如 NetComponent。然后在您的活动中提供 getNetComponent.inject() 。由于 NetComponent 将从 AppComponent 派生,因此它将提供您需要的 appComponent 的所有依赖项

    它有点复杂,但它是正确的方法,你也应该了解 Dagger Scopes。

    将网络依赖项放入 AppComponent 的快速方法。

    【讨论】:

      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 2017-03-19
      • 2018-02-11
      • 2017-11-13
      • 2015-11-04
      相关资源
      最近更新 更多