android - Dagger 2 错误子组件可能未引用作用域绑定(bind)

标签 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)

这是我的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();
    }

}

这是我的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();
    }

}

最后是 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();
    }

}

这是 ActivityBuilder

@Module
public abstract class ActivityBuilder {

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

}

最后是 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);

}

我是 Dagger 2 的新手,我是从 Medium 的随机教程中学习的。

我在这里没有看到任何子组件。我知道子组件已生成。

此错误仅发生在 @Singleton 作用域依赖项中。

我遵循一些堆栈溢出链接并将 @Singleton 添加到 AppComponent 接口(interface)。

我该如何解决这个问题?

最佳答案

将 MoviesListActivityModule 重命名为 MoviesListApplicationModule,将其从您的 @ContributesAndroidInjector 中移除,并将其放入 AppComponent 的 modules 列表中。


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

您可以将作用域(例如您创建的@ActivityScope)添加到@ContributesAndroidInjector,dagger.android 会将它们添加到生成的子组件中,就像设置modules = {/*...*/> 将向其添加模块。但是,这不是您的问题。

首先,您将 @Singleton 添加到您的 AppComponent 是正确的;这是很常见的事情,在这里做是正确的。在此处添加 @Singleton 意味着 Dagger 将自动注意标记为 @Singleton 的绑定(bind),并在您以相同方式注释的组件中保留它们的副本。如果您要创建一个 @ActivityScope 注释并将其添加到您的子组件,Dagger 会注意使用 @ActivityScope 注释的绑定(bind)并返回相同的实例 来自同一 Activity 实例,但与 同一 Activity 的其他实例其他 Activity 类型 不同的实例。

您的问题是您正在将 @Singleton 范围内的绑定(bind) Picasso 和 TmdbService 添加到您的非范围内子组件图中。您在说什么Dagger 是在您的应用程序组件(不是您的 Activity,您的应用程序)的整个生命周期中,您应该始终返回相同的 Picasso 和 TmdbService 实例。但是,通过在子组件的模块列表而不是顶级 @Singleton @Component 上进行绑定(bind),您可以在 Dagger 尝试配置 Activity 级绑定(bind)时告知这些应用程序级对象。这同样适用于您的 NetworkModule 中的绑定(bind),它们也在您的错误消息中列出。

移动模块后,您将始终收到相同的 Picasso、TmdbService、OkHttpClient 和所有其他实例——这应该允许这些对象帮助管理缓存、批处理和运行中的请求,而您不必担心关于您正在与之交互的实例。在您的应用程序的整个生命周期中,它始终是同一个实例。

关于android - Dagger 2 错误子组件可能未引用作用域绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49783392/

相关文章:

android - Dagger2 依赖 - Gradle

dependency-injection - 将 Kotlin 与 Dagger 一起使用

android - 警告 : quick boot/snapshots not supported on this machine

android - Android Q 上 "android:useEmbeddedDex"的用途

java - Android Time Class格式化时间

android - 如何使用 AndroidInjector 在模块中获取 MainActivity

android - 当minifyEnabled为true时,版本发布错误:org.gradle.initialization.ReportedException:org.gradle.internal.exceptions.LocationAwareException:

android - 如何将我的 Android 应用程序添加到共享对话框?

java - Dagger2 看不到在其他模块中定义的带有@Provide 注解的方法。没有 @provides-annotated 方法就无法提供

android - Dagger 2 中 @Reusable 范围的用途是什么