使用RxJava2 bindToLifecycle时,Home键返回后加载框未消失的解决方法
这个问题我之前也碰到过,根源其实是bindToLifecycle的生命周期绑定策略和加载框的回调逻辑不匹配导致的,咱们一步步拆解解决:
问题原因
RxLifecycle的bindToLifecycle是自动匹配生命周期的绑定策略:比如你在onResume时发起订阅,它会自动在onPause时解除订阅;如果在onStart订阅,就会在onStop时取消。当你按下Home键,页面进入后台,系统会触发onPause/onStop生命周期,此时订阅被强制解除,异步任务的onComplete/onError回调就不会再执行了——而你关闭加载框的逻辑大概率是放在这两个回调里的,所以加载框就一直停留在界面上了。
可行的解决方案
方案一:修改生命周期绑定策略,延迟解除订阅
既然后台时的生命周期触发导致订阅被取消,那我们可以把订阅的解除时机延后到页面真正销毁的时候,而不是后台时。
你可以在现有的工具方法基础上,新增一个绑定到销毁事件的方法:
public static <T> LifecycleTransformer<T> bindUntilDestroy(ZKBaseView view) { if (view instanceof RxAppCompatActivity) { // Activity绑定到ON_DESTROY事件,只有页面销毁时才解除订阅 return ((RxAppCompatActivity) view).bindUntilEvent(Lifecycle.Event.ON_DESTROY); } else if (view instanceof RxFragment) { // Fragment绑定到ON_DESTROY_VIEW事件,视图销毁时解除订阅 return ((RxFragment) view).bindUntilEvent(Lifecycle.Event.ON_DESTROY_VIEW); } else { throw new IllegalArgumentException("view isn't activity or fragment"); } }
之后发起RxJava请求时,用bindUntilDestroy(view)代替原来的bindToLifecycle(view)。这样即使按下Home键进入后台,订阅不会被取消,当异步任务完成时,onComplete/onError回调依然会执行,加载框就能正常关闭了。
方案二:在生命周期回调中兜底关闭加载框
如果不想修改RxJava的绑定策略,也可以在页面的生命周期方法里手动兜底处理加载框。比如在BaseActivity或BaseFragment的onStop方法中,判断加载框是否显示,强制关闭:
@Override protected void onStop() { super.onStop(); // 假设你的加载框实例是loadingDialog if (loadingDialog != null && loadingDialog.isShowing()) { loadingDialog.dismiss(); } }
这样不管订阅有没有被取消,只要页面进入后台(触发onStop),加载框都会被关闭,避免出现残留的情况。
方案三:结合两种方式(推荐)
把方案一和方案二结合起来,既能保证异步任务完成后正常关闭加载框,又能在页面后台时兜底处理,避免极端情况(比如任务一直未完成,页面长期后台)下加载框残留。
内容的提问来源于stack exchange,提问作者gnmmdk

