LiveData does not take the callback

The LiveData framework used in the new project, one day I discovered that the listening callback registered by LiveData only goes out once, and never goes away afterward. This is very strange. So I went to find out the reason. Finally, it was found that it was caused by try catch.

Sample code:

My code probably looks like this: try catch  is used in the method  to prevent crashes

    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

After debugging, I found that as long as it crashes for the first time, this callback will never be used again. So the bug must be related to tyr catch.

Let's look at the methods of distributing events in LiveData. And when debugging at the location marked below, it was found that mDispatchingValue has always been true, resulting in the inability to execute the next step. And mDispatchingValue is a global variable. So where is this value set to false? As shown in the mark in the following method, it will only be set to false after the entire method is executed.

 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
    }

So now the problem is very clear, it is because it crashed when calling the method, causing the catch to go directly, and the subsequent code was not executed, which resulted in the dispatchingValue method not being executed to the end, and mDispatchingValue has always been true.

Solution:

So how can we avoid a crash and make a correction at the same time?

We wrap it with try catch where the registered callback crashes , so that we can completely ensure that dispatchingValue is executed.

    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")
    }

We encapsulate and rewrite a LiveData extension function, as shown in the following method, in order to give the callback method a try catch to ensure that the callback method can be completed and avoid the dispatchingValue from not being completed: 

fun <T> MutableLiveData<T>.safeObserve(owner: LifecycleOwner, onChange: (T) -> Unit) {
    this.observe(owner) {
        try {
            onChange(it)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

Guess you like

Origin blog.csdn.net/xueyoubangbang/article/details/129713106