繁体   English   中英

Android - 无法将接口 class 注入模块

[英]Android - cannot inject Interface class into module

我是 Koin 的新手,所以希望有人能够指出我遇到的问题的方向。

我有一个接口 class:

interface UserApi {

    @POST("/refreshToken")
    @Headers("Accept: application/json")
    suspend fun refreshToken(@Body x: X): TokenResponseDto
}

我有一个 class ,我在其中使用UserApi进行 API 调用。

class TokenAuthenticator(
    private val userApi: UserApi
) : Authenticator {

    override fun authenticate(route: Route?, response: Response): Request?  = synchronized(this) {
        runBlocking { userApi.refreshToken() }
    }
}

到目前为止一切都很好,但现在我想注入TokenAuthenticator class。 如果我出于测试目的删除构造函数,我可以看到应用程序正在运行并且一切都很好,但是当我添加 userApi 构造函数变量时——我需要它,我得到并出错。

我的 NetworkModule 看起来像这样:

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

    single(named("httpClient")) {
        val tokenAuthenticator: TokenAuthenticator = get()

        OkHttpClient.Builder()
            .authenticator(tokenAuthenticator)
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    single {
        TokenAuthenticator(get())
    }
}

错误:

at org.koin.core.instance.SingleInstanceFactory$get$1.invoke(SingleInstanceFactory.kt:53)

更新:有人建议在 TokenAuthenticator 中使用 lambda function。 我认为这个解决方案更简单。

class TokenAuthenticator(
    private val userApi : () -> UserApi
) {
    // ...
  fun authenticate(...) {
    userApi().refreshToken()
  }
}

在这种情况下,您可以像这样定义您的 koin 定义。

single {
    TokenAuthenticator { 
        get() 
    }
}

我的回答是

可能有更好的解决方案,但这是一个匆忙的解决方案。 你可以改进它。

让我们解耦TokenAuthenticatorUserApi 它们稍后将通过TokenRefresher连接。

interface TokenRefresher {
  fun refreshToken()
}

class TokenAuthenticator(
        private val tokenRefresher: TokenRefresher
) : Authenticator {

    override fun authenticate(route: Route?, response: Response): Request?  = synchronized(this) {
        runBlocking { tokenRefresher.refreshToken() }
    }
}

在 koin 模块中添加一个令牌刷新器。

val networkModule = module {
    single<TokenRefresher> {
        object : TokenRefresher {

            // now use the userApi
            override fun refreshToken() {
                val userApi: UserApi = get()
                userApi.refreshToken()
            }
        }
    }

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

    single(named("httpClient")) {
        val tokenAuthenticator: TokenAuthenticator = get()

        OkHttpClient.Builder()
            .authenticator(tokenAuthenticator)
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    single {
        TokenAuthenticator(get())
    }

}

希望能帮助到你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM