![](/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.