Dagger 2错误子组件可能不引用范围绑定

Sri*_*m R 5 android dagger-2

我在我的应用程序中使用Dagger2来提供依赖项.我构建应用程序时出现以下错误.

    e: /Users/sriramr/Desktop/android/Movie/MovieInfo/app/build/generated/source/kapt/debug/in/sriram/movieinfo/di/ActivityBuilder_BindMoviesListActivity.java:22: error: in.sriram.movieinfo.di.ActivityBuilder_BindMoviesListActivity.MoviesListActivitySubcomponent (unscoped) may not reference scoped bindings:
  @Subcomponent(modules = MoviesListActivityModule.class)
  ^
      @Provides @Singleton in.sriram.movieinfo.network.TmdbService in.sriram.movieinfo.di.MoviesListActivityModule.getTmdbService(retrofit2.Retrofit)
      @Provides @Singleton retrofit2.Retrofit in.sriram.movieinfo.di.NetworkModule.getRetrofit(okhttp3.OkHttpClient, retrofit2.converter.gson.GsonConverterFactory, retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory)
      @Provides @Singleton okhttp3.OkHttpClient in.sriram.movieinfo.di.NetworkModule.getOkHttpClient(okhttp3.logging.HttpLoggingInterceptor, okhttp3.Cache)
      @Provides @Singleton okhttp3.logging.HttpLoggingInterceptor in.sriram.movieinfo.di.NetworkModule.getHttpLoggingInterceptor()
      @Provides @Singleton okhttp3.Cache in.sriram.movieinfo.di.NetworkModule.getCacheFile(@Named("application-context") android.content.Context)
      @Provides @Singleton retrofit2.converter.gson.GsonConverterFactory in.sriram.movieinfo.di.NetworkModule.getGsonConverterFactory()
      @Provides @Singleton retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory in.sriram.movieinfo.di.NetworkModule.getRxJavaFactory()
      @Provides @Singleton in.sriram.movieinfo.cache.AppDatabase in.sriram.movieinfo.di.ContextModule.getAppDatabase(@Named("application-context") android.content.Context)
      @Provides @Singleton com.squareup.picasso.Picasso in.sriram.movieinfo.di.MoviesListActivityModule.getPicasso(@Named("application-context") android.content.Context)
Run Code Online (Sandbox Code Playgroud)

这是我的 ContextModule

@Module
public class ContextModule {

    @Provides
    @Named("application-context")
    Context getContext(Application app) {
        return app;
    }

    @Provides
    @Singleton
    AppDatabase getAppDatabase(@Named("application-context") Context context) {
        return Room.databaseBuilder(context,
                AppDatabase.class, "database-name").build();
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的 NetworkModule

@Module(includes = ContextModule.class)
public class NetworkModule {

    @Provides
    @Singleton
    Cache getCacheFile(@Named("application-context") Context context) {
        File cacheFile = new File(context.getCacheDir(), "moviedb-cache");
        return new Cache(cacheFile, 10 * 1000 * 1000);
    }

    @Provides
    @Singleton
    OkHttp3Downloader getOkHttp3Downloader(OkHttpClient okHttpClient) {
        return new OkHttp3Downloader(okHttpClient);
    }

    @Provides
    @Singleton
    OkHttpClient getOkHttpClient(HttpLoggingInterceptor loggingInterceptor, Cache cache) {
        return new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .cache(cache)
                .build();
    }

    @Provides
    @Singleton
    Retrofit getRetrofit(OkHttpClient client, GsonConverterFactory gsonConverterFactory, RxJava2CallAdapterFactory callAdapter) {
        return new Retrofit.Builder()
                .addConverterFactory(gsonConverterFactory)
                .addCallAdapterFactory(callAdapter)
                .baseUrl("https://api.themoviedb.org/3/")
                .client(client)
                .build();
    }

    @Provides
    @Singleton
    HttpLoggingInterceptor getHttpLoggingInterceptor() {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> Timber.tag("OkHttp").d(message));
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return loggingInterceptor;
    }


    @Provides
    @Singleton
    GsonConverterFactory getGsonConverterFactory() {
        return GsonConverterFactory.create();
    }

    @Provides
    @Singleton
    RxJava2CallAdapterFactory getRxJavaFactory() {
        return RxJava2CallAdapterFactory.create();
    }

}
Run Code Online (Sandbox Code Playgroud)

最后是 MovieListActivityModule

@Module(includes = NetworkModule.class)
public class MoviesListActivityModule {

    @Provides
    @Singleton
    TmdbService getTmdbService(Retrofit retrofit) {
        return retrofit.create(TmdbService.class);
    }

    @Provides
    @Singleton
    Picasso getPicasso(@Named("application-context") Context context) {
        return new Picasso.Builder(context)
                .loggingEnabled(true)
                .build();
    }

}
Run Code Online (Sandbox Code Playgroud)

这是ActivityBuilder班级

@Module
public abstract class ActivityBuilder {

    @ContributesAndroidInjector(modules = MoviesListActivityModule.class)
    abstract MoviesListActivity bindMoviesListActivity();

}
Run Code Online (Sandbox Code Playgroud)

最后是AppComponent

@Singleton
@Component(modules = {AndroidInjectionModule.class, ContextModule.class, ActivityBuilder.class})
public interface AppComponent {

    @Component.Builder
    interface Builder {

        @BindsInstance
        Builder application(Application application);

        AppComponent build();

    }

    void inject(MovieInfoApp app);

}
Run Code Online (Sandbox Code Playgroud)

我是Dagger 2的新手,我从随机的Medium教程中了解到了这一点.

我在这里看不到任何SubComponent.我知道子组件是生成的.

对于@Singleton作用域依赖项,只会发生此错误.

我跟着一些堆栈溢出链接并添加@Singleton到AppComponent接口.

我该如何解决?

Jef*_*ica 19

将MoviesListActivityModule重命名为MoviesListApplicationModule,将其从您的内容中取出@ContributesAndroidInjector,然后将其放入AppComponent的modules列表中.


在幕后,@ContributesAndroidInjector生成一个@Subcomponent特定于您的MoviesListActivity.当您尝试使用时注入MoviesListActivity时AndroidInjection.inject(Activity),Dagger会创建一个子组件实例,该实例包含MoviesListActivity的MembersInjector(生成的代码,知道如何填充@InjectMoviesListActivity中的所有字段)以及您的Activity(或其依赖项)可能需要的任何范围绑定.这是你缺少的组件,它以模块和@ContributesAndroidInjector方法名称命名ActivityBuilder_BindMoviesListActivity.MoviesListActivitySubcomponent.

您可以添加范围(如@ActivityScope您创建的)@ContributesAndroidInjector,并且dagger.android会将它们添加到生成的子组件中,就像设置modules = {/*...*/}将模块添加到其上一样.但是,这不是你的问题.

首先,您添加@Singleton到AppComponent 是正确的; 这是一个非常普遍的事情,在这里做是正确的.添加@Singleton意味着Dagger会自动注意标记的绑定,@Singleton并将它们的副本保存在您以相同方式注释的组件中.如果要创建@ActivityScope注释并将其添加到子组件,Dagger会注意带有注释的绑定@ActivityScope从同一个Activity实例中返回相同的实例,但是与同一个Activity其他Activity的其他实例相比,它们会返回不同的实例类型.

你的问题是,您要添加@Singleton-scoped绑定毕加索和TmdbService 您的未范围子图.您告诉Dagger的是,在应用程序组件的生命周期内(而不是您的Activity,您的应用程序),您应该始终返回相同的Picasso和TmdbService实例.但是,通过在子组件的模块列表而不是顶级组件上进行绑定,@Singleton @Component可以在尝试配置活动级别绑定时告诉Dagger这些应用程序级别的对象.这同样适用于NetworkModule中的绑定,这些绑定也会在错误消息中列出.

移动模块后,您将始终收到Picasso,TmdbService,OkHttpClient以及所有其他实例的相同实例 - 这些实例应允许这些对象帮助管理缓存中的缓存,批处理和请求,而无需担心哪个实例你正在与之互动.在应用的整个生命周期中,它始终是相同的实例.