RXJava中Single取消订阅后doAfterTerminate为何未被调用?
问题原因分析&解决方案
嘿,这个问题我之前在项目里踩过坑,咱们一步步来捋清楚哈~
为什么计数器没递减?
核心原因在于RxJava 1中doAfterTerminate和subscriber.unsubscribe()的触发逻辑完全不同:
doAfterTerminate只会在序列正常终止时执行——也就是当Single发送了onSuccess或者onError信号之后,才会触发这个回调。- 而你在
onError里调用subscriber.unsubscribe()属于主动取消订阅,这个操作会直接切断订阅关系,不属于“序列正常终止”的流程,所以doAfterTerminate根本不会被执行,计数器自然就没机会递减了。
怎么解决?
有两种靠谱的方案,根据你的需求选就行:
方案1:用doOnUnsubscribe补充取消订阅时的处理
doOnUnsubscribe会在订阅被取消时触发——不管是序列正常终止后自动取消,还是你手动调用unsubscribe取消。你可以把计数器递减的逻辑同时放到doAfterTerminate和doOnUnsubscribe里,但要注意避免重复递减:
update(..) .doOnSubscribe(() -> counter++) .doAfterTerminate(() -> { // 正常终止时递减,判断状态避免重复 if (!subscriber.isUnsubscribed()) { counter--; } }) .doOnUnsubscribe(() -> counter--) // 手动取消时递减 .subscribe();
不过这个方案需要判断订阅状态,有点繁琐,更推荐下面的方案。
方案2:用Single.using统一管理计数器
using操作符专门用来管理资源的创建和释放,不管序列是正常完成、出错还是被取消,都会执行资源释放逻辑,完美匹配你的计数器场景:
Single.using( // 订阅开始时:计数器加一 () -> { counter++; // 这里不需要实际资源,返回null就行 return null; }, // 执行你的update操作 resource -> update(..), // 订阅结束时(无论何种原因):计数器减一 resource -> counter-- ) .subscribe();
用这个方案的话,你就不用再操心手动取消订阅的情况了,所有场景下计数器都会正确增减。
额外提醒
如果你以后升级到RxJava 2+,可以直接用doFinally操作符,它就是专门用来处理“无论序列如何结束都要执行的逻辑”,比上面的方案更简洁~
内容的提问来源于stack exchange,提问作者justmee
相关产品推荐
相关产品推荐

