如何在retryWhen中刷新Observable参数,实现自动登录后更新原参数
使用retryWhen实现带参数更新的自动登录功能
我最近在做RxJava相关的功能,想要用retryWhen实现一个自动登录的逻辑——就是当接口返回401未授权时,自动调用登录接口,登录成功后更新原请求的参数(比如带上新拿到的token),再重新发起原来的请求。我先写了个TestClass的框架代码,大概是这样:
class TestClass(): Function<Flowable<out Throwable>, Flowable<*>> { override fun apply(flowable: Flowable<out Throwable>): Flowable<*> { return flowable .flatMap { if (it is HttpException && it.code() == 401 ) { Timber.d("apply: Doing AutoLogin.") dataSource.login(document, password) // 这里需要处理登录成功后更新原请求参数的逻辑 } else { // 非401错误直接抛出,不重试 Flowable.error(it) } } } }
这里的核心难点是:retryWhen默认只能触发重试,但没法直接修改原Observable的请求参数。我摸索出了一套可行的实现方案,分享给大家:
实现思路
- 把原请求的动态参数(比如token)封装成线程安全的可变容器,这样登录成功后可以直接更新容器内的值;
- 在
retryWhen的逻辑里,完成自动登录后更新参数容器,再返回触发重试的信号; - 原请求的Observable每次都从参数容器中读取最新值,确保重试时用的是更新后的参数。
完整代码示例
// 定义线程安全的参数容器,存储需要动态更新的请求参数 class RequestParamsHolder { // 用AtomicReference保证多线程环境下的参数读写安全 val token = AtomicReference<String?>() // 可扩展其他需要动态更新的参数,比如登录凭证、请求签名等 } // 改造后的自动登录重试处理器 class AutoLoginRetryHandler( private val dataSource: LoginDataSource, private val paramsHolder: RequestParamsHolder, // 提供获取最新登录凭证的方法(比如从本地缓存读取) private val getLoginCredentials: () -> Pair<String, String> ) : Function<Flowable<out Throwable>, Flowable<*>> { override fun apply(errors: Flowable<out Throwable>): Flowable<*> { return errors.flatMap { throwable -> when { // 仅处理401未授权错误 throwable is HttpException && throwable.code() == 401 -> { Timber.d("触发自动登录流程") val (document, password) = getLoginCredentials() // 执行自动登录请求 dataSource.login(document, password) .doOnSuccess { loginResult -> // 登录成功后更新参数容器中的token paramsHolder.token.set(loginResult.token) Timber.d("自动登录成功,已更新请求token") } // 登录成功后返回信号,触发原请求重试 .map { Unit } // 登录失败则直接抛出错误,终止重试流程 .onErrorReturn { Flowable.error(it) } } // 非401错误直接抛出,不进行重试 else -> Flowable.error(throwable) } } } } // 使用示例:发起需要自动登录重试的请求 fun makeAuthorizedRequest(paramsHolder: RequestParamsHolder): Flowable<ApiResponse> { return apiService.fetchData( // 每次请求都从参数容器中读取最新的token token = paramsHolder.token.get() ?: "" ) .retryWhen(AutoLoginRetryHandler(dataSource, paramsHolder) { // 这里从本地缓存(比如SharedPreferences)获取登录凭证 Pair("user_document", "user_password") }) }
关键细节说明
- 参数容器的线程安全:用
AtomicReference是因为RxJava的操作可能在不同线程执行,它能避免参数读写时的线程安全问题; - 重试触发逻辑:登录成功后返回的
Unit信号会通知retryWhen重新订阅原Observable,而原请求会自动读取参数容器里的最新值,实现带新参数的重试; - 避免无限循环:如果自动登录失败(比如密码过期、账号锁定),直接抛出错误终止重试,不会陷入死循环。
内容的提问来源于stack exchange,提问作者Gibran Lyra
相关产品推荐
相关产品推荐

