新项目使用的LiveData这个框架,有一天发现LiveData注册的监听回调,永远只走一次,后面的都不走了,这个很奇怪。于是去查找原因。最后发现是try catch引起的。
示例代码:
我的代码大概如下所示:方法中使用了try catch 来防止奔溃
val mBanner=MutableLiveData<List<Banner>>()
fun test(){
println("1")
try {
mBanner.observe(this){
println("2")
throw RuntimeException("奔溃了")
println("3")
}
}catch (e:Exception){
}
println("4")
}
//打印的结果: 1,2,4
debug后发现只要第一次奔溃后,后面永远都不会走这个回调。所以说因为bug肯定和tyr catch有关。
我们查看LiveData中分发事件的方法。并且debug在如下标记的位置,发现mDispatchingValue一直是true,导致执行不了下一步。而且mDispatchingValue是一个全局变量。那么这个值在哪里置为false呢?如下方法中标记所示,只有在整个方法执行完才会置为false
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) { //在此处debug
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue()); //分发事件
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false; //方法执行完毕后置为falses
}
所以现在问题就很明确了,就是因为调用方法的 时候奔溃了,导致直接走了catch,后面的代码没有执行完,从而导致dispatchingValue 方法没有执行到底,mDispatchingValue就一直为 true了。
解决方法:
那么如何实现即避免奔溃,同时能走回调呢?
我们在注册回调奔溃的地方再用try catch包住,这样就能完整的保证dispatchingValue执行完毕。
val mBanner=MutableLiveData<List<Banner>>()
fun test(){
println("1")
try {
mBanner.observe(this){
try {
println("2")
throw RuntimeException("奔溃了")
println("3")
}catch (e:Exception){
}
}
}catch (e:Exception){
}
println("4")
}
我们封装下,重写一个LiveData的扩展函数,如下的方法所示,为的就是给回调的方法给try catch下,保证这个回调方法能执行完,避免dispatchingValue执行不完:
fun <T> MutableLiveData<T>.safeObserve(owner: LifecycleOwner, onChange: (T) -> Unit) {
this.observe(owner) {
try {
onChange(it)
} catch (e: Exception) {
e.printStackTrace()
}
}
}