Dagger generating multiple instances of retrofit interceptor

梦想的初衷 提交于 2019-12-20 04:43:05

问题


I am new to Dagger and Retrofit. I am having issue where multiple instances of retrofit custom interceptor are being generated despite declared singleton in dagger module. I only require one instance.

Dagger Module

@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();
    }
}

Retrofit Interceptor

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

Connector

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

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

/** Setting interceptor headers here, but this get sets in a different instances than the one gets called later in 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);
        }
    }

}

And in my Application I create instance of Dagger like this:

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

And in my MainActivity I create instance of Connect

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

Now the problem is that AuthenticationRequestInterceptor contructor gets called twice which I don't understand why and because of that the headers that I set get sets to a different instance of Interceptor. Please help. Thanks


回答1:


You should not call provideRequestInterceptor directly

@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();
}



回答2:


There is on point creating another of instance OkHttpClient.Builder within the provideRetrofitInstance method, you have already provided it in your ApiModule. Be nice and use as httpClient argument instead.

@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();
    }
}


来源:https://stackoverflow.com/questions/45078720/dagger-generating-multiple-instances-of-retrofit-interceptor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!