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

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情

数据丢失

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

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

LiveData: observe: new str 10

这是因为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);
    }
};

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

粘性事件

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

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

protected void setValue(T value) {
	//省略其他代码
    mVersion++;
}

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

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

在我们的观察者的包装类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);
}

数据处理

如果希望在将 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
}

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

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  两个输出
}

感知生命周期

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

public interface LifecycleOwner {
    Lifecycle getLifecycle();
}

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

public interface LifecycleEventObserver extends LifecycleObserver {
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

猜你喜欢

转载自juejin.im/post/7113722376411414536