You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用Koin时无法将UserApi接口注入TokenAuthenticator类

解决Koin循环依赖问题:UserApi、OkHttpClient与TokenAuthenticator的依赖闭环

问题分析

你遇到的是典型的循环依赖问题,依赖链为:UserApi → 带Authenticator的httpClient → TokenAuthenticator → UserApi,Koin无法处理这种闭环依赖,导致实例创建失败。

解决方案

方案1:用Koin懒加载注入打破循环

修改TokenAuthenticator,将构造函数注入改为Koin的懒加载注入,初始化时不会立即请求UserApi实例,从而打破循环:

class TokenAuthenticator : Authenticator {
    // 用by inject()懒加载UserApi,替代构造函数注入
    private val userApi: UserApi by inject()

    override fun authenticate(route: Route?, response: Response): Request? = synchronized(this) {
        // 注意补充refreshToken所需的X参数
        val tokenResponse = runBlocking { userApi.refreshToken(yourXInstance) }
        // 补充根据新令牌重新构建请求的逻辑(原代码省略了这部分)
        response.request.newBuilder()
            .header("Authorization", "Bearer ${tokenResponse.token}")
            .build()
    }
}

对应的Koin模块配置调整:

val networkModule = module {
    single<UserApi> {
        Retrofit.Builder()
            .client(get(named("httpClient")))
            .baseUrl(get<String>(named("...")))
            .addConverterFactory(...)
            .build()
            .create(UserApi::class.java)
    }

    single(named("httpClient")) {
        OkHttpClient.Builder()
            .authenticator(get<TokenAuthenticator>())
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    // 现在TokenAuthenticator不需要构造参数
    single { TokenAuthenticator() }
}

方案2:拆分HttpClient(更符合业务逻辑)

从业务角度看,刷新令牌的接口本身不应该需要认证,否则会陷入「认证失败→刷新令牌→再次认证失败」的死循环。因此可以拆分出两个HttpClient:

  1. 基础HttpClient:不带Authenticator,专门供刷新令牌的UserApi使用
  2. 认证HttpClient:带TokenAuthenticator,供其他需要认证的接口使用

修改后的NetworkModule配置:

val networkModule = module {
    // 1. 基础HttpClient:无Authenticator,供UserApi使用
    single(named("baseHttpClient")) {
        OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    // 2. UserApi依赖基础HttpClient,彻底避免循环
    single<UserApi> {
        Retrofit.Builder()
            .client(get(named("baseHttpClient")))
            .baseUrl(get<String>(named("...")))
            .addConverterFactory(...)
            .build()
            .create(UserApi::class.java)
    }

    // 3. TokenAuthenticator正常依赖UserApi
    single { TokenAuthenticator(get()) }

    // 4. 认证HttpClient:带Authenticator,供其他需要认证的API使用
    single(named("authHttpClient")) {
        OkHttpClient.Builder()
            .authenticator(get<TokenAuthenticator>())
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

这个方案既解决了循环依赖,又贴合业务逻辑——刷新令牌接口本身不需要携带旧令牌,用基础HttpClient发起请求即可。

内容的提问来源于stack exchange,提问作者MaaAn13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 07:54:09