当前位置:网站首页>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);
}
边栏推荐
- 在IPhone12的推理延迟仅为1.6 ms!Snap等详析Transformer结构延迟,并用NAS搜出移动设备的高效网络结构...
- Anhui "requirements for design depth of Hefei fabricated building construction drawing review" was printed and distributed; Hebei Hengshui city adjusts the pre-sale license standard for prefabricated
- Unity Shader - 踩坑 - BRP 管线中的 depth texture 的精度问题(暂无解决方案,推荐换 URP)
- SGD has many improved forms. Why do most papers still use SGD?
- Collectors. Tomap application
- SQL必需掌握的100个重要知识点:插入数据
- 深潜Kotlin协程(十七):演员
- LVGL 8.2 Image
- Every time I look at my colleagues' interface documents, I get confused and have a lot of problems...
- [rust daily] the first rust monthly magazine on January 22, 2021 invites everyone to participate
猜你喜欢
List介绍
Rejuvenated Dell and apple hit each other, and the two old PC enterprises declined rapidly
煥發青春的戴爾和蘋果夾擊,兩大老牌PC企業極速衰敗
智能DNA分子纳米机器人模型来了
matplotlib 笔记: contourf & contour
20万奖金池!【阿里安全 × ICDM 2022】大规模电商图上的风险商品检测赛火热报名中!...
中国将强制统一充电接口,苹果如不低头,iPhone将被踢出中国市场
[STL source code analysis] container (to be supplemented)
The reasoning delay on iphone12 is only 1.6 MS! Snap et al. Analyzed the transformer structure latency in detail, and used NAS to find out the efficient network structure of mobile devices
科普达人丨漫画图解什么是eRDMA?
随机推荐
【STL源码剖析】迭代器
Jetpack Compose DropdownMenu跟随手指点击位置显示
国产自研系统的用户突破4亿,打破美国企业的垄断,谷歌后悔不迭
【无标题】
电化学氧气传感器寿命、工作原理及应用介绍
JS FAQs
从开源项目探讨“FPGA挖矿”的本质
LVGL 8.2 Simple Image button
我们公司使用 7 年的这套通用解决方案,打通了几十个系统,稳的一批!
20万奖金池!【阿里安全 × ICDM 2022】大规模电商图上的风险商品检测赛火热报名中!...
语音信号处理-基础(五):傅立叶变换
When does the database need to use the index [Hangzhou multi surveyors] [Hangzhou multi surveyors _ Wang Sir]
语音识别-基础(一):简介【语音转文本】
8行代码实现快速排序,简单易懂图解!
【leetcode 239】滑动窗口
LVGL 8.2 Simple Image button
SQL必需掌握的100个重要知识点:使用存储过程
Mysql database foundation: TCL transaction control language
电商两位大佬花边新闻刷屏,代表电商回归正常,将有利于实体经济
pytorch 笔记 torch.nn.BatchNorm1d