无法提供匕首改装

Posted

技术标签:

【中文标题】无法提供匕首改装【英文标题】: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);


    

【问题讨论】:

【参考方案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 的快速方法。

【讨论】:

以上是关于无法提供匕首改装的主要内容,如果未能解决你的问题,请参考以下文章

匕首刀柄:注释类@Singleton 和提供函数@Singleton 之间的区别

无法实例化应用程序匕首android

PIX无损线控改装——全系列车型及性能介绍

联想ThinkPad E440怎么加装SSD固态硬盘改装双硬盘?

线控性能比拼,MKZ与CRV作为自动驾驶开发平台的全面测评

适合改装的Scott Spark RC,最轻量化和最技术流