![](/img/trans.png)
[英]Dagger injection ViewModel Factory compile time error (dependency cycle in dagger)
[英]How to remove Dagger Hilt dependency Injection cycle
我有一個提供ApiService
實例的網絡模塊 class。 有一個Authenticator
class,它在過期時刷新訪問令牌。 身份驗證器需要ApiService
實例來進行 API 調用。 這會導致循環依賴。 如何避免這種情況?
現在我在TokenExpiryAuthenticator
class 中創建一個新的ApiService
來進行 API 調用,以打破循環依賴。 如何正確地將ApiService
注入TokenExpiryAuthenticator
而不會導致循環依賴?
@InstallIn(SingletonComponent::class)
@Module
object NetworkModule {
@Provides
@Singleton
@Named("Other")
fun provideRetrofitWithoutInterceptor(@Named("Other") client: OkHttpClient, gson: Gson): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient, gson: Gson): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
@Provides
@Singleton
fun providesOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor, supportInterceptor: SupportInterceptor, tokenExpiryAuthenticator: TokenExpiryAuthenticator): OkHttpClient {
return OkHttpClient.Builder().writeTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.callTimeout(1, TimeUnit.MINUTES)
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(supportInterceptor)
.authenticator(tokenExpiryAuthenticator)
.build()
}
@Named("Other")
@Provides
@Singleton
fun providesOkHttpClientWithoutInterceptor(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder().writeTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.callTimeout(1, TimeUnit.MINUTES)
.addInterceptor(httpLoggingInterceptor)
.build()
}
@Provides
@Singleton
fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor {
return if (BuildConfig.DEBUG)
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
else
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.NONE
}
}
@Provides
@Singleton
fun providesGson(): Gson {
return GsonBuilder().create()
}
@Provides
@Singleton
fun providesRestApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
@Provides
@Singleton
@Named("Other")
fun providesRestApiServiceWithoutInterceptor(@Named("Other") retrofit: Retrofit): ApiService{
return retrofit.create(ApiService::class.java)
}
}
您可以拆分 ApiService 並創建一個新的 AuthenticationApi,它僅包含用於驗證或刷新訪問令牌的端點。 此 AuthenticationApi 是使用沒有 Authenticator 的 OkHttp 實例創建的。
這樣你的身份驗證器只需要參考這個苗條的 Retrofit api。這也保證你不會得到 HTTP 401 身份驗證循環,以防在使用身份驗證端點時出現錯誤的憑據。
最簡單的解決方案是延遲注入依賴項。
class TokenExpiryAuthenticator @Inject constructor(
private val api: Lazy<ApiService>,
private val persistence: TokenPersistenceRepository
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
// If HTTP 401 error was raised while trying to refresh token it means
// the token is invalid (or expired). Sign out user and do not
// proceed with further requests.
if (response.request.url.encodedPath == REFRESH_TOKEN_PATH) {
// Perform any cleanup needed.
// Return null so no further requests will be performed.
return null
}
// Request failed for old token. It's about time to refresh it.
if (response.request.header(AUTH_HEADER) != null) {
// Refresh access token using your lazily injected service.
persistence
.retrieveRefreshToken()
.flatMap(api.get()::refreshToken)
.flatMapCompletable {
Completable.concatArray(
persistence.saveAccessToken(it.accessToken),
persistence.saveRefreshToken(it.refreshToken),
)
}
.blockingAwait()
// You can use blocking await as the [authenticate] method is
// run on I/O thread anyway.
}
// Load recently refreshed access token.
val token = (...)
// Format authorization header value.
val header = (...)
// Modify and proceed with a request with refreshed access token.
return response.request.newBuilder()
.removeHeader(AUTH_HEADER)
.addHeader(AUTH_HEADER, header)
.build()
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.