RxJava - 在某些方法完成后返回

时间:2018-04-04 08:06:06

标签: android kotlin rx-java2

我是RxJava的新手,我尝试使用我的Android / Kotlin应用程序中的刷新令牌实现OAuth2流程。

我在拦截器中刷新访问令牌时遇到了一些困难(我为OAuthAuthenticator内的每个API请求添加了访问令牌)。问题是我想等待填充请求,直到令牌请求完成。

有人会暗示我如何实现这个目标吗?

这是我的身份验证员类:

class OAuthAuthenticator(
        private val authStateManager: AuthStateManager,
        private val authRepository: AuthRepository): Authenticator {

    override fun authenticate(route: Route?, response: Response?): Request? {

        // handle invalid token
        if (response != null && response.code() == 401) {
            println("Invalid access token")

            authRepository.refreshToken()
                    .subscribe { _ ->
                        println("Token refreshed")
                    }
        }

        // this should happen after the token request is completed since it would fail again otherwise
        return response?.request()!!
                .newBuilder()
                .header("Authorization", "Bearer " + authStateManager.current.accessToken)
                .build()
    }
}

2 个答案:

答案 0 :(得分:0)

您正在同步方法中进行异步调用。那不会奏效。在rx链中完成令牌请求后,您必须放置要执行的代码。

class OAuthAuthenticator(
        private val authStateManager: AuthStateManager,
        private val authRepository: AuthRepository) : Authenticator {

        override fun authenticate(route: Route?, response: Response?): Single<Request> {
            // handle invalid token
            if (response != null && response.code() == 401) {
                return Single.error(InvalidAccessTokenException("Invalid access token"))
            }

            return Single.fromCallable { authRepository.refreshAccessToken() }
                .subscribeOn(Schedulers.computation())
                .map {
                    return@map response?.request()!!
                        .newBuilder()
                        .header("Authorization", "Bearer " +
                                authStateManager.current.accessToken)
                        .build()
                }
        }
    }

然后你可以这样称呼它:

val authenticator = OAuthAuthenticator(authStateManager, authRepository)
val disposable = authenticator.authenticate(route, response)
            .subscribe({ _ ->
                println("Token refreshed")
            }, { error ->
                if (error is InvalidAccessTokenException) {
                    println("Invalid access token")
                } else {
                    println("Could not refresh token. Signing out...")
                    authStateManager.signOut()
                }
            })

答案 1 :(得分:0)

您可以使用blockingGet()使Single同步。但不建议这样做。但是,因为您使用

在本地创建Single
Single.fromCallable { authRepository.refreshAccessToken() }

你可以直接调用适当的方法而不用 Rx 包装它。

if (response != null && response.code() == 401) {
    println("Invalid access token")
    try {
        authRepository.refreshAccessToken()
        println("Token refreshed")
    } catch(error: Throwable) {
        println("Could not refresh token. Signing out...")
        authStateManager.signOut()
        return null
    }
}