【问题标题】:Android Dagger 2 Injecting in InterceptorAndroid Dagger 2 在拦截器中注入
【发布时间】:2022-01-16 12:25:33
【问题描述】:

我只是在拦截器中注入存储库以在需要或过期时获取访问令牌时遇到问题。我只是不明白我在哪里做错了。我只是没有找到任何示例如何处理拦截器和存储库。想想那个双重“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 取决于RefreshTokenApi 取决于Retrofit 取决于OkHttpClient 取决于... HeaderInterceptor - 循环完成。使用不存在循环依赖问题的方式刷新令牌 - 可能是不包含拦截器的不同 Okhttpclient 实例 - 这很容易在 Dagger 中使用 @Qualifier@Named 注释完成。
  • HeaderInterceptor 对 TwichHeaderRepository 的依赖乍一看似乎是一个非常奇怪的设计选择。你能解释一下这个设计选择吗?

标签: android dependency-injection dagger-2 interceptor


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 2018-12-08
    • 1970-01-01
    • 2015-10-10
    相关资源
    最近更新 更多