本文介绍了Android Dagger2 + OkHttp + Retrofit依赖周期错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Hey there I am using Dagger2, Retrofit and OkHttp and I am facing dependency cycle issue.

提供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界面:

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,但是在创建APIService时需要提供TokenAuthenticator.这会导致依赖性循环错误.我该如何打败,有人面对这个问题吗?预先感谢.

So my question: My TokenAuthenticator class is depends on APIService but I need to provide TokenAuthenticator when creating APIService. This causes dependency cycle error. How do I beat this , is there anyone facing this issue ?Thanks in advance.

推荐答案

您的问题是:

  1. 您的OKHttpClient取决于您的身份验证器
  2. 您的身份验证器取决于翻新服务
  3. 改造依赖于OKHttpClient(如第1点所述)

因此具有循环依赖性.

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

One possible solution here is for your TokenAuthenticator to depend on an APIServiceHolder rather than a APIService. Then your TokenAuthenticator can be provided as a dependency when configuring OKHttpClient regardless of whether the APIService (further down the object graph) has been instantiated or not.

一个非常简单的APIServiceHolder:

A very simple APIServiceHolder:

public class APIServiceHolder {

    private APIService apiService;

    @Nullable
    APIService apiService() {
        return apiService;
    }

    void setAPIService(APIService apiService) {
        this.apiService = apiService;
    }
}

然后重构您的TokenAuthenticator:

Then refactor your 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;
}

请注意,检索令牌的代码应同步.这是Authenticator合同的一部分. Authenticator中的代码将在主线程中关闭.

Note that the code to retrieve the token should be synchronous. This is part of the contract of Authenticator. The code inside the Authenticator will run off the main thread.

当然,您需要为此编写@Provides方法:

Of course you will need to write the @Provides methods for the same:

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

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

Note that mutable global state is not usually a good idea. However, if you have your packages organised well you may be able to use access modifiers appropriately to avoid unintended usages of the holder.

这篇关于Android Dagger2 + OkHttp + Retrofit依赖周期错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-07 20:05