当前位置:网站首页>LiveData源码赏析三 —— 常见问题
LiveData源码赏析三 —— 常见问题
2022-06-30 10:39:00 【Android每日一讲】
数据丢失
通过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);
}
边栏推荐
猜你喜欢
![[understanding of opportunity -34]: fate is within the light cone](/img/3e/9f5630ba382df7f7ce00705445cef8.jpg)
[understanding of opportunity -34]: fate is within the light cone

Pytorch Notebook. Nn. Batchnorm1d

Review of mathematical knowledge: curve integral of the second type
![200000 bonus pool! [Alibaba security × ICDM 2022] the risk commodity inspection competition on the large-scale e-commerce map is in hot registration](/img/0e/19c4c97a582d7b2ad08ce806d7af03.jpg)
200000 bonus pool! [Alibaba security × ICDM 2022] the risk commodity inspection competition on the large-scale e-commerce map is in hot registration

OceanBase 安装 yum 源配置错误及解决办法

WireGuard简单配置

焕发青春的戴尔和苹果夹击,两大老牌PC企业极速衰败

Go zero micro Service Practice Series (VIII. How to handle tens of thousands of order requests per second)

在IPhone12的推理延迟仅为1.6 ms!Snap等详析Transformer结构延迟,并用NAS搜出移动设备的高效网络结构...
![[STL source code analysis] container (to be supplemented)](/img/69/0c6e0e8ecb3ebc8c9b8503f5a8b4e5.jpg)
[STL source code analysis] container (to be supplemented)
随机推荐
基于HAL库的LED驱动库
IDEA 又出新神器,一套代码适应多端!
CSDN blog operation team 2022 H1 summary
sCrypt 中的 ECDSA 签名验证
LVGL 8.2 Drop down in four directions
Double-DQN笔记
From introduction to mastery of MySQL 50 lectures (32) -scylladb production environment cluster building
LVGL 8.2 Image styling and offset
WireGuard简单配置
Viewing technological changes through Huawei Corps (V): smart Park
单片机 MCU 固件打包脚本软件
深潜Kotlin协程(十八):冷热数据流
Unity Shader - 踩坑 - BRP 管线中的 depth texture 的精度问题(暂无解决方案,推荐换 URP)
语音识别-基础(一):简介【语音转文本】
OLAP数据库引擎如何选型?
LED driver library based on Hal Library
SGD has many improved forms. Why do most papers still use SGD?
【Proteus仿真】Arduino UNO LED模拟交通灯
JS FAQs
数学知识复习:第二型曲线积分