Android中RXJava2嵌套Completable未被调用问题排查
onUserAuthenticated未执行的问题 嘿,我来帮你分析一下为什么onUserAuthenticated始终没被调用!从你的代码来看,问题大概率出在RxJava链条的构建逻辑或者数据源的返回类型上,下面我一步步拆解:
可能的问题根源
1. userRepository.getCurrentUser()的返回类型不符合预期
你需要获取用户详情对象传给onUserAuthenticated,但如果getCurrentUser()返回的是Completable,它不会发射任何数据——这意味着flatMapCompletable的lambda参数(也就是你代码里的it)根本不存在,后续逻辑自然不会执行。
如果getCurrentUser()返回的是Maybe<User>,还有一种情况:当没有用户数据返回时,Maybe会直接进入完成状态,不会触发flatMapCompletable的lambda,导致onUserAuthenticated被跳过。
2. 冗余的Completable.defer使用
你用Completable.defer包裹了onUserAuthenticated调用和Completable.complete(),这完全是多余的。defer的作用是延迟创建Completable实例,但这里你只是执行一个同步方法,直接用Completable.fromAction更直观,也避免了不必要的延迟逻辑可能带来的隐藏问题。
3. 链条中发生错误但未被察觉
如果authRepository.login()或者userRepository.getCurrentUser()执行出错,错误会沿着Completable链条传递到订阅的onError回调。但你的LoginViewModel里只打印了简单的错误日志,可能你没注意到错误发生,误以为是onUserAuthenticated没执行。
修复方案
步骤1:修正getCurrentUser()的返回类型与处理逻辑
确保userRepository.getCurrentUser()返回Single<User>(登录成功后理应能获取到用户数据);如果必须用Maybe<User>,一定要添加空数据处理:
override fun login(email: String, password: String): Completable { // 先做字段非空校验 if (email.isBlank() || password.isBlank()) { return Completable.error(IllegalArgumentException("邮箱或密码不能为空")) } return authRepository.login(email, password) // 假设authRepository.login返回Single<Token> .flatMapCompletable { token -> userRepository.getCurrentUser() // 处理Maybe<User>空数据的情况(如果用Single可以省略这一步) .switchIfEmpty(Single.error(IllegalStateException("登录后未找到用户数据"))) .flatMapCompletable { user -> // 用fromAction替代冗余的defer Completable.fromAction { authentication.onUserAuthenticated(AuthType.EMAIL, user, token) } } } }
步骤2:优化错误日志排查
在LoginViewModel的订阅回调里添加更详细的错误信息,方便快速定位问题:
fun login() { val emailVal = email.value val passwordVal = password.value // 避免用!!强制非空,防止空指针 if (emailVal.isNullOrBlank() || passwordVal.isNullOrBlank()) { Timber.w("登录失败:邮箱或密码为空") return } emailAuthentication.login(email = emailVal, password = passwordVal) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ Timber.d("用户${emailVal}登录成功") }, { error -> Timber.e(error, "用户${emailVal}登录失败:${error.message}") }) }
步骤3:验证数据源的正确性
在authRepository.login()和userRepository.getCurrentUser()的实现里添加日志,确认它们能正常返回令牌和用户数据——如果这两个方法本身没正确执行,整个链条都会卡住。
额外建议
- 永远不要用
!!强制非空,像上面代码那样用空判断处理,避免不必要的崩溃; - 如果
onUserAuthenticated是异步方法,不要直接在fromAction里调用,要把它包装成Completable/Single,确保异步操作完成后再通知链条结束。
内容的提问来源于stack exchange,提问作者Alex Burdusel

