【问题标题】:Dagger generating multiple instances of retrofit interceptorDagger 生成多个改装拦截器实例
【发布时间】:2017-12-18 02:58:00
【问题描述】:

我是 Dagger 和 Retrofit 的新手。尽管在匕首模块中声明了单例,但我遇到了生成多个改装自定义拦截器实例的问题。我只需要一个实例。

匕首模块

@Module
public class ApiModule
{
    private Config config;

    public ApiModule(Config config) {
        this.config = config;
    }

    @Provides @Singleton
    public OkHttpClient.Builder provideOkHttpClient()
    {
        return new OkHttpClient.Builder();
    }

    @Provides @Singleton
    public AuthenticationRequestInterceptor provideRequestInterceptor()
    {
        return new AuthenticationRequestInterceptor();
    }

    @Provides @Singleton
    public Retrofit provideRetrofitInstance()
    {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        // set your desired log level
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

        // add session headers interceptor
        httpClient.addInterceptor(provideRequestInterceptor());

        // add logging as last interceptor
        httpClient.addInterceptor(logging);  

        return new Retrofit.Builder()
                .baseUrl(getConfig().getBaseUrl())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClient.build()) //for logging purpose remove later
                .build();
    }
}

改装拦截器

public class AuthenticationRequestInterceptor implements Interceptor
{
    private Map<String, String> defaultHeaders;

    public AuthenticationRequestInterceptor()
    {
        this.defaultHeaders = new HashMap<>();
    }

    public void setDefaultHeaders(Map<String, String> headers)
    {
        this.defaultHeaders = headers;
    }

    @Override
    public Response intercept(Chain chain) throws IOException
    {
        Request request = chain.request();

        Request.Builder requestBuilder = request.newBuilder();

        for (String key: this.defaultHeaders.keySet())
        {
            requestBuilder.addHeader(key, this.defaultHeaders.get(key));
        }

        return chain.proceed(requestBuilder.build());
    }
}

连接器

public class Connect
{
    @Inject Retrofit retrofit;
    @Inject Config config;
    @Inject AuthenticationRequestInterceptor headerInterceptor;

    public Connect(PercentApp application)
    {
        ((PercentApp) application).getComponent().inject(this);

/** 在此处设置拦截器标头,但这会以不同的方式设置 实例比稍后在 postUser 中调用的实例 **/

     headerInterceptor.setDefaultHeaders(generateDefaultAuthHeaders());
    }

    public void postUser(Observer observer, User user)
    {
        if(retrofit != null)
        {
            ApiServices api = retrofit.create(ApiServices.class);
            Observable<HashMap> observable = api.postUser("{post something}");
            observable.
                    subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer);
        }
    }

}

在我的应用程序中,我创建了这样的 Dagger 实例:

DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .apiModule(new ApiModule(new Config(environment)))
                .build();

在我的 MainActivity 中,我创建了 Connect 实例

Connect connect = new Connect((MyApp) getApplication());
User user = new User();
connect.postUser(new UserObserver(this), user);

现在的问题是 AuthenticationRequestInterceptor 构造函数被调用了两次,我不明白为什么,因为我设置的标头被设置为不同的拦截器实例。请帮忙。谢谢

【问题讨论】:

    标签: android retrofit2 dagger-2 rx-java2


    【解决方案1】:

    你不应该直接打电话给provideRequestInterceptor

    @Provides @Singleton
    public Retrofit provideRetrofitInstance(AuthenticationRequestInterceptor authInterceptor)
    {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        // set your desired log level
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    
        // add session headers interceptor
        httpClient.addInterceptor(authInterceptor);
    
        // add logging as last interceptor
        httpClient.addInterceptor(logging);  
    
        return new Retrofit.Builder()
                .baseUrl(getConfig().getBaseUrl())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClient.build()) //for logging purpose remove later
                .build();
    }
    

    【讨论】:

    • 我不明白为什么当我在 dagger 中将 requestInterceptor 声明为 @singleton 时,为什么要创建它的多个实例。我们不能在同一个模块中调用另一个提供者吗?
    • Dagger2 不能作为 Spring 工作(在 Spring 中,当您调用它代理它的方法时,您不会 直接 调用真正的方法)。让 Dagger2 做它的事。如果您需要一个对象,请在方法的参数中声明它
    • @user606669 如果您想从一个提供者中获取另一个提供者的值,那么您应该将此值放入参数列表(将我的代码与您的代码进行比较)。对于 Singletone annotation Dagger 检查生成代码中的方法调用,它无法检查您的代码,因为它使用编译时注入,而不是运行时。
    • 通过注入retrofit,该实例已经拥有拦截器。如果您还想要拦截器实例,则必须以与注入 retrofit 相同的方式注入
    • @user606669 你可能会看到 Dagger 如何在生成的类 ApiModule_ProvideRetrofitInstanceFactory 中进行注入(参见build/generated/source/apt/debug
    【解决方案2】:

    在provideRetrofitInstance方法中创建另一个实例OkHttpClient.Builder,你已经在你的ApiModule中提供了它。最好使用 httpClient 参数。

    @Module
    public class ApiModule
    {
       private Config config;
    
       public ApiModule(Config config) {
          this.config = config;
       }
    
       @Provides @Singleton
       public OkHttpClient.Builder provideOkHttpClient()
       {
          return new OkHttpClient.Builder();
       }
    
       @Provides @Singleton
       public AuthenticationRequestInterceptor provideRequestInterceptor()
       {
          return new AuthenticationRequestInterceptor();
       }
    
       @Provides @Singleton
       public Retrofit provideRetrofitInstance(OkHttpClient.Builder httpClient, 
            AuthenticationRequestInterceptor authInterceptor)
       {
           HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
           // set your desired log level
           logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
    
            //YOU DON'T THIS LINE, REFER TO ARGUMENT LIST
           //OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    
    
          // add session headers interceptor
          httpClient.addInterceptor(authInterceptor);
    
          // add logging as last interceptor
          httpClient.addInterceptor(logging);  
    
          return new Retrofit.Builder()
                .baseUrl(getConfig().getBaseUrl())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(httpClient.build()) //for logging purpose remove later
                .build();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2021-10-28
      • 1970-01-01
      • 2017-11-22
      相关资源
      最近更新 更多