Android Jetpack之LiveData源码分析
创始人
2024-04-12 03:33:21
0

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 activity 和 fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。

LiveData 的优势:

  • 确保界面符合数据状态
  • 不会发生内存泄漏
  • 不会因 Activity停止而导致崩溃
  • 不再需要手动处理生命周期
  • 数据始终保持最新状态
  • 适当的配置更改
  • 共享资源

以上内容均来自官网,官网地址

在这里插入图片描述
通过之前的博客:LiveData的简单使用。我们了解了LiveData的基本使用。这里回顾一下

LiveData的简单实用(一般都是跟ViewModel一起实用)


public class LiveDataActivity extends AppCompatActivity {private TextView mTextContent;//使用LiveDataprivate MutableLiveData contentLiveData = new MutableLiveData<>();@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_livedata_test);mTextContent = findViewById(R.id.tv_content);//设置 观察者contentLiveData.observe(this, new Observer() {@Overridepublic void onChanged(String s) {mTextContent.setText(s);}});//点击按钮,改变内容findViewById(R.id.btn_livedata_change).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {contentLiveData.setValue("内容改变了");}});}
}

下面的源码分析中,有些情况会设计到Lifecycle()监控生命周期。有兴趣的可以看下:Android Jetpack之Lifecycle的使用及源码分析

下面,我们通过上面使用的步骤,来分析。LiveData内容都做了什么操作

  • 一、分析观察者LiveData#observe方法
  • 二、分析通过set/postValue 方法改变内容

一、设置observe()方法

添加观察者,并且我们无需关系,移除及内存泄露问题

下面看下源码

private SafeIterableMap, ObserverWrapper> mObservers =new SafeIterableMap<>();...@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {assertMainThread("observe");//owner是Activity已经实现的(Lifecycle文章有说)//如果owner的生命周期已经结束的话,直接返回。避免了内存泄露,甚至Crashif (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}//wrapper包装类。里面主要是一些生命周期及版本的判断LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//这里,我们看到添加观察者的时候。是把观察者做key,放到了一个Map里面ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);if (existing != null && !existing.isAttachedTo(owner)) {throw new IllegalArgumentException("Cannot add the same observer"+ " with different lifecycles");}if (existing != null) {return;}//这里跟我们添加Lifecycle()一样,可以让wrapper监听owner生命周期,做一些判断owner.getLifecycle().addObserver(wrapper);}

看到这里,其实发现很简单,添加观察者,其实,就是在LiveData里面创建了一个Map,把观察者存进去。

Map的值是个包含了owner(这里就是Activity,方便理解)和观察者observer的封装类。

二、分析通过set/postValue()改变内容

下面,我们看看LiveData的setValue()方法,是怎么把值传递过去的

public class MutableLiveData extends LiveData {@Overridepublic void setValue(T value) {super.setValue(value);}
}

这里调用了super.setValue()继续看

    @MainThreadprotected void setValue(T value) {assertMainThread("setValue");//这里的版本,后面会说mVersion++;mData = value;dispatchingValue(null);}

这里做了2个事情:

1,把值赋值给mData
2,调用 dispatchingValue(null);

我们接着看下

  void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;//initiator这里通过上面知道,传递的是null。所以,走elseif (initiator != null) {considerNotify(initiator);initiator = null;} else {//把所有观察者的Map,通过迭代器遍历for (Iterator, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}

这里,我们可以看到,dispatchingValue()方法就是,遍历观察者所在的Map,然后,调用considerNotify()方法。

看下considerNotify()方法

 private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {return;}// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.//// we still first check observer.active to keep it as the entrance for events. So even if// the observer moved to an active state, if we've not received that event, we better not// notify for a more predictable notification order.if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;//通过上面一系列的判断,最终调用了观察者的onChanged方法。observer.mObserver.onChanged((T) mData);}

这里,我们可以看到通过一些列生命周期的判断,版本的判断,最终调用了观察者的onChange()方法。
到这里,我们就已经走通了,所有的调用流程。

postValue的全过程跟setValue类似。只不过是后面通过Handler切换到了主线程上

在这里插入图片描述

[未完成]
上面有一点东西,我们没有说,那就是观察者observer的mLastVersion跟数据的mVersion问题。这个也是造成粘性数据的原因。但是,它跟EventBus不同的是,EventBus是提供了粘性数据的开关,但是,它并没有。

问题:LiveData的数据倒灌/粘性数据问题。

场景:(列表–详情(修改数据)–返回并点击其它列表–再次进入详情)(使用ShareViewModel)

SingleLiveEvent(解决一次事件,只消费一次),当注册多个观察者后,只有一个会受到,非常容易出错。

UnPeek-LiveData 解决方案

相关内容

热门资讯

宇树科技被起诉,什么原因? 涉及侵权责任纠纷案件 投资时间网、标点财经快讯 天眼查法律诉讼信息显示,近日,杭州宇树科技股份有限公...
惠城环保:已制定《市值管理制度... 证券之星消息,惠城环保(300779)12月31日在投资者关系平台上答复投资者关心的问题。 投资者提...
看2026|和尔解王倩:降低调... 站在“十五五”新程待启的关键时点,如何看待2026年的经济形势?2026年经济工作怎么干?新京报贝壳...
奇瑞汽车申请满足软件升级法规要... 国家知识产权局信息显示,奇瑞汽车股份有限公司申请一项名为“一种满足软件升级法规要求的升级测试优化方法...
国台办:公安机关发布悬赏通告并... 12月31日上午,国台办在新闻发布厅举行例行新闻发布会,发言人张晗就近期两岸热点问题回答记者提问。 ...
元旦前发布这种朋友圈,他们面临... 元旦即将到来 不少人想买点烟花爆竹 增添节日氛围 朋友圈里也出现了 各种烟花爆竹的广告 但你知道吗 ...
“护航”增值税法顺利实施 配套... 新华社北京12月31日电 《经济参考报》12月31日刊发记者韦夏怡采写的文章《“护航”增值税法顺利实...
《山东省行政调解办法》5月1日... 在我们的日常生活中,难免会遇到各种纠纷,调解作为重要的纠纷解决方式,在维护群众权益方面发挥了重要作用...
上海发文推进老年人意定监护制度... 12月31日,上海市政府官网发布《上海市人民政府办公厅关于推进实施老年人意定监护制度的若干意见(试行...