【问题标题】:Android Dagger2 error: @javax.inject.Named("BaseUrl") java.lang.String is bound multiple timesAndroid Dagger2 错误:@javax.inject.Named("BaseUrl") java.lang.String 被绑定多次
【发布时间】:2016-09-16 08:22:53
【问题描述】:

我正在用 Dagger2 尝试一些东西,但仍然难以理解..

我想在 2 个类中使用 2 个服务,SplashActivity 和 HomeActivity。 服务依赖于 NetModule,因为我想重用改造和 okhttpclient 提供。

这是我的网络模块:

@Module
public class NetModule {
    @Provides
    Retrofit provideRetrofit(@Named("BaseUrl") String baseUrl, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    @Provides
    HttpLoggingInterceptor provideHttpLoggingInterceptor() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        } else {
            logging.setLevel(HttpLoggingInterceptor.Level.NONE);
        }

        return logging;
    }

    @Provides
    OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor, @Named("ConnectTimeoutMs") int connectTimeoutMs, @Named("ReadTimeoutMs") int readTimeoutMs) {
        return new OkHttpClient.Builder()
                .addInterceptor(httpLoggingInterceptor)
                .connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS)
                .readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS)
                .build();
    }
}

StaticDataModule 和 StatusModule,这是两个不同的 API,所以他们使用 NetModule:

@Module(includes = NetModule.class)
public class StaticDataModule {
    @Provides
    @Singleton
    StaticDataService provideStaticDataService(Retrofit retrofit) {
        return new RetrofitStaticDataService(retrofit);
    }

    @Provides
    @Named("BaseUrl")
    String provideBaseUrl() {
        return "http://url_static.com";
    }

    @Provides
    @Named("ConnectTimeoutMs")
    int provideConnectTimeoutMs() {
        return 5000;
    }

    @Provides
    @Named("ReadTimeoutMs")
    int provideReadTimeoutMs() {
        return 5000;
    }
}

@Module(includes = NetModule.class)
public class StatusModule {
    @Provides
    @Singleton
    StatusService provideStatusService(Retrofit retrofit) {
        return new RetrofitStatusService(retrofit);
    }

    @Provides
    @Named("BaseUrl")
    String provideBaseUrl() {
        return "http://url_status.com";
    }

    @Provides
    @Named("ConnectTimeoutMs")
    int provideConnectTimeoutMs() {
        return 5000;
    }

    @Provides
    @Named("ReadTimeoutMs")
    int provideReadTimeoutMs() {
        return 5000;
    }
}

我在这个组件中构建它们:

@Singleton
@Component(modules = {AppModule.class, StaticDataModule.class, StatusModule.class})
public interface AppComponent {
    void inject(SplashActivity splashActivity);
    void inject(HomeActivity homeActivity);
}

我收到此错误:@javax.inject.Named("BaseUrl") java.lang.String 被绑定多次。 我理解我的错误,dagger 不知道 StaticData baseUrl 和 Status baseUrl 之间是谁提供的。

我尝试制作 2 个组件,StaticDataComponent 和 StatusComponent,但我无法在同一个 Activity 中同时注入这两个组件。

我尝试在 StaticDataModule 和 StatusModule 中扩展 NetModule,并使用构造函数提供参数,但在改造提供时出现多个边界错误。

所以我不知道如何在 2 个模块中重用具有不同参数的 NetModule,如果有人有示例,它应该对我有帮助。

谢谢!

【问题讨论】:

  • 最简单的事情,你可以做:将名称更改为 StatusBaseUrl 和 StaticBaseUrl
  • 但是在 NetModule for baseUrl 我需要什么?我必须写 @Named("Something") 不?
  • 或者不,使用相同的名称,但不要将 NetModule 作为依赖项。用于一个组件(NetModule + 状态模块),用于第二个组件(NetModule + 静态模块)
  • 是的,这可以创建 2 个服务,但问题是注入。如果我让 NetModule+StatusModule 注入 MainActivity 和 NetModule+StaticModule 注入 MainActivity 它不起作用,2个组件不能注入同一个类..那是我的问题=(或者组件有办法注入父级?
  • 当你遇到这种情况时,这意味着你最好重新设计你的架构:) 解决方案可以是,你不要像往常一样注入,而是作为方法提供

标签: java android dagger-2


【解决方案1】:

不要将 NetModule.class 作为模块的依赖项包含在内,只需将它们单独包含在组件中即可。

@Module(includes = NetModule.class)
public class StaticDataModule {

@Module
public class StaticDataModule {

然后像这样使用:

@Component(modules = {
    NetModule.class, StaticDataModule.class
}) public interface FirstComponent {
  void inject(WhateverYouWantActivity activity);
}

@Component(modules = {
    NetModule.class, StatusModule.class
}) public interface FirstComponent {
  void inject(WhateverYouWantSecondActivity activity);
}

如果你必须注入相同的活动,你最好重新设计你的架构,但如果你仍然想这样做,你可以去掉注入方法,并添加如下内容:

@Component(modules = { /* your modules */ }) public interface YourComponent {

  Retrofit getRetrofit();

  OkHttpClient getOkHttpClient();
}

并相应地使用它:

retrofit = yourComponentBuiltByDagger.getRetrofit();

代替:

@Inject Retrofit retrofit;

【讨论】:

  • 好的,我会这样做的。也许我可以尝试用他们自己的 provideRetrofit 来制作 StaticDataModule 和 StatusModule ,但名称不同,就像你以前的 anwser 一样。唯一的问题是,我必须为每个使用改造的 api 服务重新定义 providerRetrofit ..
  • 你对一项活动进行了两次改造?
  • 我只是想避免将改造链接到活动,如果我想通过另一个库更改改造,我只想在模块中进行更改。
  • @Lyofen 你真的不需要改造,注入ApiService接口
【解决方案2】:

最后我找到了一个简单的解决方案,我的架构很糟糕。现在我只需要一个模块,并且不提供改造,他在 StaticData 和 Status 实现中构建:

@Module
public class NetModule {
    @Provides
    HttpLoggingInterceptor provideHttpLoggingInterceptor() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        } else {
            logging.setLevel(HttpLoggingInterceptor.Level.NONE);
        }

        return logging;
    }

    @Provides
    OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor) {
        return new OkHttpClient.Builder()
                .addInterceptor(httpLoggingInterceptor)
                .connectTimeout(5000, TimeUnit.MILLISECONDS)
                .readTimeout(5000, TimeUnit.MILLISECONDS)
                .build();
    }

    @Provides
    @Singleton
    StaticDataService provideStaticDataService(OkHttpClient okHttpClient) {
        return new RetrofitStaticDataService("http://url_1.com",okHttpClient);
    }

    @Provides
    @Singleton
    StatusService provideStatusService(OkHttpClient okHttpClient) {
        return new RetrofitStatusService("http://url_2.com",okHttpClient);
    }

}

@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
    void inject(SplashActivity splashActivity);
    void inject(HomeActivity homeActivity);
}

Retrofit 对象仅在改造实现类中,所以如果我需要通过另一个库更改改造,我只需通过 new AnotherStaticDataService() 更改 new RetrofitStaticDataService()。

感谢安东的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    相关资源
    最近更新 更多