嘿,我正在使用Dagger2RetrofitOkHttp,并且我面临着依赖周期问题。

提供OkHttp时:

@Provides
@ApplicationScope
OkHttpClient provideOkHttpClient(TokenAuthenticator auth,Dispatcher dispatcher){
    return new OkHttpClient.Builder()
            .connectTimeout(Constants.CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(Constants.READ_TIMEOUT,TimeUnit.SECONDS)
            .writeTimeout(Constants.WRITE_TIMEOUT,TimeUnit.SECONDS)
            .authenticator(auth)
            .dispatcher(dispatcher)
            .build();
}

提供Retrofit时:
@Provides
@ApplicationScope
Retrofit provideRetrofit(Resources resources,Gson gson, OkHttpClient okHttpClient){
    return new Retrofit.Builder()
            .baseUrl(resources.getString(R.string.base_api_url))
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(okHttpClient)
            .build();
}

提供APIService时:
@Provides
@ApplicationScope
APIService provideAPI(Retrofit retrofit) {
    return retrofit.create(APIService.class);
}

我的APIService接口(interface):
public interface  APIService {
@FormUrlEncoded
@POST("token")
Observable<Response<UserTokenResponse>> refreshUserToken();

--- other methods like login, register ---

}

我的TokenAuthenticator类:
@Inject
public TokenAuthenticator(APIService mApi,@NonNull ImmediateSchedulerProvider mSchedulerProvider) {
    this.mApi= mApi;
    this.mSchedulerProvider=mSchedulerProvider;
    mDisposables=new CompositeDisposable();
}

@Override
public  Request authenticate(Route route, Response response) throws IOException {

    request = null;

    mApi.refreshUserToken(...)
            .subscribeOn(mSchedulerProvider.io())
            .observeOn(mSchedulerProvider.ui())
            .doOnSubscribe(d -> mDisposables.add(d))
            .subscribe(tokenResponse -> {
                if(tokenResponse.isSuccessful()) {
                    saveUserToken(tokenResponse.body());
                    request = response.request().newBuilder()
                            .header("Authorization", getUserAccessToken())
                            .build();
                } else {
                    logoutUser();
                }
            },error -> {

            },() -> {});

    mDisposables.clear();
    stop();
    return request;

}

我的logcat:
Error:(55, 16) error: Found a dependency cycle:
com.yasinkacmaz.myapp.service.APIService is injected at com.yasinkacmaz.myapp.darkvane.modules.NetworkModule.provideTokenAuthenticator(…, mApi, …)
com.yasinkacmaz.myapp.service.token.TokenAuthenticator is injected at
com.yasinkacmaz.myapp.darkvane.modules.NetworkModule.provideOkHttpClient(…, tokenAuthenticator, …)
okhttp3.OkHttpClient is injected at
com.yasinkacmaz.myapp.darkvane.modules.NetworkModule.provideRetrofit(…, okHttpClient)
retrofit2.Retrofit is injected at
com.yasinkacmaz.myapp.darkvane.modules.NetworkModule.provideAPI(retrofit)
com.yasinkacmaz.myapp.service.APIService is provided at
com.yasinkacmaz.myapp.darkvane.components.ApplicationComponent.exposeAPI()

所以我的问题是:我的TokenAuthenticator类取决于APIService,但是在创建TokenAuthenticator时需要提供APIService。这会导致依赖性循环错误。我该如何打败,有人面对这个问题吗?
提前致谢。

最佳答案

您的问题是:

  • 您的OKHttpClient取决于您的身份验证器
  • 您的身份验证器取决于翻新服务
  • 改型依赖于OKHttpClient(如第1点所示)

  • 因此,循环依赖。

    一种可能的解决方案是让TokenAuthenticator依赖APIServiceHolder而不是APIService。然后,可以在配置TokenAuthenticator时将OKHttpClient作为依赖项提供,而不管APIService(在对象图的下方)是否已实例化。

    一个非常简单的APIServiceHolder:
    public class APIServiceHolder {
    
        private APIService apiService;
    
        @Nullable
        APIService apiService() {
            return apiService;
        }
    
        void setAPIService(APIService apiService) {
            this.apiService = apiService;
        }
    }
    

    然后重构您的TokenAuthenticator:
    @Inject
    public TokenAuthenticator(@NonNull APIServiceHolder apiServiceHolder, @NonNull ImmediateSchedulerProvider schedulerProvider) {
        this.apiServiceHolder = apiServiceHolder;
        this.schedulerProvider = schedulerProvider;
        this.disposables = new CompositeDisposable();
    }
    
    @Override
    public  Request authenticate(Route route, Response response) throws IOException {
    
        if (apiServiceHolder.get() == null) {
             //we cannot answer the challenge as no token service is available
    
             return null //as per contract of Retrofit Authenticator interface for when unable to contest a challenge
        }
    
        request = null;
    
        TokenResponse tokenResponse = apiServiceHolder.get().blockingGet()
    
        if (tokenResponse.isSuccessful()) {
            saveUserToken(tokenResponse.body());
            request = response.request().newBuilder()
                         .header("Authorization", getUserAccessToken())
                         .build();
        } else {
           logoutUser();
        }
    
        return request;
    }
    

    请注意,用于检索 token 的代码应为同步。这是Authenticator契约(Contract)的一部分。 Authenticator中的代码将在主线程的上运行

    当然,您将需要编写相同的@Provides方法:
    @Provides
    @ApplicationScope
    apiServiceHolder() {
        return new APIServiceHolder();
    }
    

    并重构提供者方法:
    @Provides
    @ApplicationScope
    APIService provideAPI(Retrofit retrofit, APIServiceHolder apiServiceHolder) {
        APIService apiService = retrofit.create(APIService.class);
        apiServiceHolder.setAPIService(apiService);
        return apiService;
    }
    

    注意,可变的全局状态通常不是一个好主意。但是,如果您的包裹安排得井井有条,则可以适当使用访问修饰符,以避免意外使用持有人。

    关于android - Android Dagger2 + OkHttp + Retrofit依赖周期错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43914605/

    10-12 06:11