• LiveData源码赏析三 —— 常见问题


    数据丢失

    通过postValue()方法更新LiveData数据的时候,可能存在数据丢失的情况。

    val liveData = MutableLiveData()
    Thread {
        for (index in 0..9) {
            liveData.postValue("new str $index")
        }
    }.start()
    liveData.observe(this) {
        Log.i("LiveData", "observe: $it")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们连续调用了postValue()10次,但是结果只有最后一次的数据。

    LiveData: observe: new str 10
    
    • 1

    这是因为postValue()方法内部其实是将数据回调的逻辑放到了Runnable中,再post给Handler,利用Handler在主线程中更新,因此从postValue()到执行Runnable,中间是存在时间差的。在这段时间内通过postValue()方法更新数据仅仅会改变LiveData内部的值,而不会再次post一个新的Runnable。

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    private final Runnable mPostValueRunnable = new Runnable() {
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    只有当Runnable被执行了mPendingData才会被赋值为NOT_SET,这样在postValue()的时候执行postTask = mPendingData == NOT_SET才会让postTask的值为true,最后才会post一个Runnable。

    粘性事件

    发射的事件如果早于注册,那么注册之后依然可以接收到的事件称为粘性事件。

    LiveData内部是通过一个整数mVersion来记录当前数据的版本号。

    protected void setValue(T value) {
    	//省略其他代码
        mVersion++;
    }
    
    • 1
    • 2
    • 3
    • 4

    当我们调用setValue()更新数据的时候,mVersion就会自增。

    private abstract class ObserverWrapper {
        int mLastVersion = -1;
    }
    
    • 1
    • 2
    • 3

    在我们的观察者的包装类ObserverWrapper内部也维护了一个版本号mLastVersion,它记录的是上一次回调的数据的版本,初始化为-1。

    如果我们先改变LiveData的数据,那么mVersion就会自增变为1,然后注册观察者,此时观察者内部维护的版本号mLastVersion为初始值-1。最后在回调判断的时候(observer.mLastVersion >= mVersion)就会不成立,从而观察者就会收到它注册之前的数据。

    private void considerNotify(ObserverWrapper observer) {
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    数据处理

    如果希望在将 LiveData 对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData 实例,可以使用Transformations类来进行LiveData的数据处理。

    map

    map可以将LiveData内部的数据类型转换,使LiveData转换为LiveData。

    val intLiveData = MutableLiveData(1)
    val strLiveData:LiveData<String> = Transformations.map(intLiveData){
        "$it"
    }
    strLiveData.observe(this){
        println(it is String)//true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    switchMap

    switchMap()可以根据某个值,切换观察不同的LiveData数据。也可以实现LiveData转换为LiveData。

    val originLiveData = MutableLiveData(true)
    val trueLiveData = MutableLiveData("trueLiveData")
    val falseLiveData = MutableLiveData("falseLiveData")
    val distinctLiveData = Transformations.switchMap(originLiveData) {
        if (it) {
            trueLiveData
        } else {
            falseLiveData
        }
    }
    distinctLiveData.observeForever {Log.i(TAG, it)}//trueLiveData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    distinctUntilChanged

    distinctUntilChanged()方法返回一个屏蔽了原始LiveData重复数据的新LiveData。

    val boolLiveData = MutableLiveData<Boolean>()
    val distinctLiveData = Transformations.distinctUntilChanged(boolLiveData)
    Thread {
        for (index in 0..10) {
            SystemClock.sleep(100)
            boolLiveData.postValue((index < 9))
        }
    }.start()
    distinctLiveData.observe(this){
        println(it) //结果去重了  只有true 和 false  两个输出
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    感知生命周期

    LiveData.observer()方法可以感知Owner的生命周期,在调用此方法的时候会传入一个LifecycleOwner对象,LifecycleOwner是一个接口。

    public interface LifecycleOwner {
        Lifecycle getLifecycle();
    }
    
    • 1
    • 2
    • 3

    Fragment和FragmentActivity都实现了此接口并返回一个LifecycleRegistry对象,当他们生命周期发生变化的时候,会调用LifecycleRegistry.handleLifecycleEvent()方法分发生命周期给对应的生命周期观察者。回调LifecycleEventObserver的onStateChanged()方法。 而LifecycleBoundObserver实现了LifecycleEventObserver接口,所以他能接收到生命周期改变的回调。

    public interface LifecycleEventObserver extends LifecycleObserver {
        void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
    }
    
    • 1
    • 2
    • 3
  • 相关阅读:
    壳聚糖-聚乙二醇-生物素|生物素-PEG-壳聚糖|Chitosan-PEG-Biotin
    【毕业设计】天气预测与数据分析系统 - 机器学习 python
    C#连接MySql数据库详细步骤
    【杂记-浅谈Time To Live/TTL】
    Vue中使用组件的三大步骤
    LLM(大语言模型)常用评测指标-MAP@R
    蓝桥杯真题 - 费解的开关题解
    Golang的数组、切片、映射
    消息总线 —— SpringCloud Bus
    Eureka介绍和使用
  • 原文地址:https://blog.csdn.net/m0_62167422/article/details/125492633