草庐IT

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

coder 2023-12-07 原文

我在我的应用程序中使用 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 - Dagger 2 错误子组件可能未引用作用域绑定(bind)的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  6. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  7. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  8. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

  9. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  10. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

随机推荐