如何解决 Dagger (Hilt) 中的循环依赖

Wah*_*han 6 android kotlin dagger retrofit dagger-hilt

我想使用拦截器刷新我的令牌,但我的拦截器需要 API 服务来进行 API 调用。我陷入了依赖循环。

这是我的 ApplicationModule 类:

@Module
@InstallIn(ApplicationComponent::class)
class ApplicationModule {


    @Provides
    fun providerBaseUrl() = AppConstants.BASE_URL

    @Provides
    @Singleton
    fun provideOkHttpClient(authInterceptor: AuthInterceptor,
                            networkInterceptor: NetworkInterceptor) = if (BuildConfig.DEBUG) {

        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
        OkHttpClient.Builder()
                .addInterceptor(authInterceptor)
                .addInterceptor(loggingInterceptor)
                .addInterceptor(networkInterceptor)
                //   .addInterceptor(refreshTokenInterceptor) // I want to put my interceptor here
                .connectTimeout(2, TimeUnit.MINUTES)
                .readTimeout(2, TimeUnit.MINUTES)
                .writeTimeout(2, TimeUnit.MINUTES)

                .build()
    } else OkHttpClient
            .Builder()
            .connectTimeout(2, TimeUnit.MINUTES)
            .readTimeout(2, TimeUnit.MINUTES)
            .writeTimeout(2, TimeUnit.MINUTES)
            .addInterceptor(authInterceptor)
            .addInterceptor(networkInterceptor)
            .build()


    @Provides
    @Singleton
    fun provideRetrofit(
            okHttpClient: OkHttpClient,
            BASE_URL: String
    ): Retrofit =
            Retrofit.Builder()
                    .addConverterFactory(MoshiConverterFactory.create())
                    .baseUrl(BASE_URL)
                    .client(okHttpClient)
                    .build()

    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): WebApi = retrofit.create(WebApi::class.java)


      @Provides
      @Singleton // this is my provider
      fun provideRefreshTokenService(webApi: WebApi): RefreshTokenInterceptor {
          return RefreshTokenInterceptor(webApi)
      }

    @Provides
    fun provideAuthInterceptor(): AuthInterceptor {
        return AuthInterceptor()
    }

    @Provides
    fun provideNetWorkInterceptor(): NetworkInterceptor {
        return NetworkInterceptor()
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 RefreshTokenInterceptor:

class RefreshTokenInterceptor @Inject constructor(webApi: WebApi) : Interceptor {

    var api = webApi

    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        val updatedToken = getUpdatedToken(webApi = api)
        requestBuilder.header("Authorization", updatedToken)

        return chain.proceed(requestBuilder.build())
    }

    private fun getUpdatedToken(webApi: WebApi): String {

        GlobalScope.launch {
            val authTokenResponse = webApi.refreshToken()
            val newToken = "${authTokenResponse.body()!!.data.token}"
            SharedPref.getInstance(AppController.applicationContext()).setUserToken(newToken)

        }
        return SharedPref.getInstance(AppController.applicationContext()).getUserToken
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 7

我遇到了类似的问题并找到了解决方案。您可以使用 Lazy 接口将 api 实例包装在令牌拦截器中。这将解决您的循环依赖问题。

这是一个代码片段。

class RefreshTokenInterceptor @Inject constructor(private val webApi: Lazy<WebApi>) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        val updatedToken = getUpdatedToken(webApi = api.get())
        requestBuilder.header("Authorization", updatedToken)

        return chain.proceed(requestBuilder.build())
    }

    private fun getUpdatedToken(webApi: WebApi): String {

        GlobalScope.launch {
            val authTokenResponse = webApi.refreshToken()
            val newToken = "${authTokenResponse.body()!!.data.token}"
            SharedPref.getInstance(AppController.applicationContext()).setUserToken(newToken)

        }
        return SharedPref.getInstance(AppController.applicationContext()).getUserToken
    }
} 
Run Code Online (Sandbox Code Playgroud)


小智 -1

看这个例子:

@Provides
@Singleton
fun provideDatabase(
    @ApplicationContext context: Context,
    @RoomCreateCallback callback: RoomDatabase.Callback
) = Room.databaseBuilder(context, TaskDatabase::class.java, Constants.TaskKeys.TASK_DATABASE)
    .fallbackToDestructiveMigration()
    .addCallback(callback)
    .build()

@Provides
fun provideTaskDao(taskDatabase: TaskDatabase) = taskDatabase.taskDao()

@Provides
@Singleton
@RoomCreateCallback
fun provideDatabaseCreateCallback(
    taskDatabase: Provider<TaskDatabase>,
    @ApplicationScope applicationScope: CoroutineScope
) = object : RoomDatabase.Callback() {
    override fun onCreate(db: SupportSQLiteDatabase) {
        super.onCreate(db)

        val dao = taskDatabase.get().taskDao()

        applicationScope.launch {
            dao.insert(Task("First task"))
            dao.insert(Task("Second task"))
            dao.insert(Task("Third task", important = true))
            dao.insert(Task("Fourth task", completed = true))
            dao.insert(Task("Fifth task"))
            dao.insert(Task("Sixth task", completed = true))
            dao.insert(Task("Seventh task"))
            dao.insert(Task("Eighth task"))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

创建 RoomDatabase 时需要 RoomDatabase.Callback,但执行此回调时也需要 RoomDatabase。在 ProvideDatabaseCreateCallback() 函数中,我将 RoomDatabase 包装在 Provider<> 内。