Android Dagger 2 注入拦截器

Android Dagger 2 Injecting in Interceptor

我刚刚在拦截器中注入存储库以在需要或过期时获取访问令牌时遇到问题。我只是不明白我哪里做错了。我只是没有找到任何如何处理拦截器和存储库的示例。想想那个双“Retrofit.Builder”也许这是个问题。你怎么看?让我们来谈谈代码:

@Module
class AppModule {

@Singleton
@Provides
fun provideRefreshTokenService(client: OkHttpClient): RefreshTokenApi {
    return Retrofit.Builder()
        .baseUrl("https://id.twitch.tv/oauth2/")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(RefreshTokenApi::class.java)
}

@Singleton
@Provides
fun provideHttpClient(headerInterceptor: HeaderInterceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addNetworkInterceptor(headerInterceptor)
        .build()
}

@Singleton
@Provides
fun provideRetrofit(client: OkHttpClient): TwichApi {
    return Retrofit.Builder()
        .baseUrl("https://api.igdb.com/v4/")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(TwichApi::class.java)
}
}


    class TwichHeaderRepository @Inject constructor(
private val refreshTokenApi: RefreshTokenApi) 
 {
        suspend fun fetchRefreshToken(): Response<RefreshToken> {
            return withContext(Dispatchers.IO) {
                refreshTokenApi.getRefreshToken()
            }
        }
    }


private const val TAG = "AddRepositoryAction"
private const val HEADER_CLIENT_ID = "Client-ID"
private const val HEADER_AUTHORIZATION = "Authorization"
private const val HEADER_ACCEPT = "Accept"
private const val DEFAULT_ACCESS_TOKEN = "mjycvndz4sasons2mg990kqme6vu6d"
private const val UNAUTHORIZED_STATUS_CODE = 401

@Singleton
class HeaderInterceptor @Inject constructor(
    private val context: Context,
    private val twichHeaderRepository: TwichHeaderRepository
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {

        val response = chain.proceed(chain.request().newBuilder().apply {
            header(HEADER_CLIENT_ID, "i3nzc6w3n0pod39zgsq8h445o2yp6p")
            header(HEADER_AUTHORIZATION, "Bearer $DEFAULT_ACCESS_TOKEN")
            header(HEADER_ACCEPT, "application/json")
        }.build())

        val refreshToken = runBlocking { generateAccessToken(twichHeaderRepository) }

        if (response.code == UNAUTHORIZED_STATUS_CODE) {
            response.close()
            val accessToken = ""
            return chain.proceed(chain.request().newBuilder().apply {
                header(HEADER_CLIENT_ID, "i3nzc6w3n0pod39zgsq8h445o2yp6p")
                header(HEADER_AUTHORIZATION, "Bearer $accessToken")
                header(HEADER_ACCEPT, "application/json")
            }.build())
        }
        return response
    }
}

private suspend fun generateAccessToken(twichHeaderRepository: TwichHeaderRepository): String 
{
    val responseRefreshToken = twichHeaderRepository.fetchRefreshToken()

    return responseRefreshToken.body().toString()
}


interface RefreshTokenApi {

    @POST(
       ...
    )
    suspend fun getRefreshToken(
    ): Response<RefreshToken>

}



@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance context: Context): AppComponent
    }

    fun inject(activity: MainActivity)
    fun inject(fragment: AddFragment)
    fun inject(interceptor: HeaderInterceptor)
}



class TwichRepository @Inject constructor(
    private val twichApi: TwichApi
) {
    
    suspend fun searchGames(title: String): Response<Game> {
        return withContext(Dispatchers.IO) { twichApi.getGamesBySearch(title) }
    }
}

错误信息是

Found a dependency cycle okhttp3.OkHttpClient is injected at
              com.example.glc.AppModule.provideRefreshTokenService(client)
          com.example.glc.add.RefreshTokenApi is injected at
              com.example.glc.add.TwichHeaderRepository(refreshTokenApi)
          com.example.glc.add.TwichHeaderRepository is injected at
              com.example.glc.add.HeaderInterceptor(�, twichHeaderRepository)
          com.example.glc.add.HeaderInterceptor is injected at
              com.example.glc.AppModule.provideHttpClient(headerInterceptor)
          okhttp3.OkHttpClient is injected at
              com.example.glc.AppModule.provideRetrofit(client)
          com.example.glc.add.TwichApi is injected at
              com.example.glc.add.TwichRepository(twichApi)
          com.example.glc.add.TwichRepository is injected at
              com.example.glc.add.AddViewModel(twichRepository)
          com.example.glc.add.AddViewModel is injected at
              com.example.glc.add.AddFragment.addViewModel
          com.example.glc.add.AddFragment is injected at
              com.example.glc.di.AppComponent.inject(com.example.glc.add.AddFragment)

您在 HeaderInterceptor 的构造函数中对 TwichHeaderRepository 依赖使用 Lazy 来打破依赖循环。

class HeaderInterceptor @Inject constructor(
    private val lazyTwichHeaderRepository: Lazy<TwichHeaderRepository>
) {
    // Access the dependency lazily with lazyTwichHeaderRepository.get()
}

我只需要添加 @Named 来解决我的问题并理解它,就像马克在评论中所说的那样。

@Module

class 应用模块 {

@Singleton
@Provides
@Named("oauth2")
fun provideAccessTokenHttpClient() = OkHttpClient.Builder().build()

@Singleton
@Provides
fun provideRefreshTokenService(@Named("oauth2") client: OkHttpClient): RefreshTokenApi {
    return Retrofit.Builder()
        .baseUrl("https://id.twitch.tv/oauth2/")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(RefreshTokenApi::class.java)
}

@Singleton
@Provides
@Named("igdb")
fun provideSearchDataHttpClient(headerInterceptor: HeaderInterceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(headerInterceptor)
        .build()
}

@Singleton
@Provides
fun provideRetrofit(@Named("igdb") client: OkHttpClient): TwichApi {
    return Retrofit.Builder()
        .baseUrl("https://api.igdb.com/v4/")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(TwichApi::class.java)
}

}