framework通信机制—LiveData使用方法及原理

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

使用 LiveData 的优势

使用 LiveData 具有以下优势:

  • 确保界面符合数据状态LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知Observer对象。您可以整合代码以在这些Observer对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
  • 不会发生内存泄漏观察者会绑定到Lifecycle对象,并在其关联的生命周期遭到销毁后进行自我清理。
  • 不会因 Activity 停止而导致崩溃如果观察者的生命周期处于非活跃状态(如返回堆栈中的 activity),它便不会接收任何 LiveData 事件。
  • 不再需要手动处理生命周期界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
  • 数据始终保持最新状态如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
  • 适当的配置更改如果由于配置更改(如设备旋转)而重新创建了 activity 或 fragment,它会立即接收最新的可用数据。
  • 共享资源您可以使用单例模式扩展LiveData对象以封装系统服务,以便在应用中共享它们。LiveData对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData对象。如需了解详情,请参阅扩展 LiveData。

LiveData的几种用法

声明一个LiveData

我们发现LiveData是一个抽象类,它的默认实现子类是MutableLiveData,但是看源码他们没有区别~唯一区别就是set和post方法公开了,之所以这么设计,是考虑到单一开闭原则,只有拿到 MutableLiveData 对象才可以发送消息,LiveData 对象只能接收消息,避免拿到 LiveData 对象时既能发消息也能收消息的混乱使用。

//1.声明一个MutableLiveData
val data = MutableLiveData("Test")fun main(){//2.监听数据源变化data.observe(this){ data->//...do somethig}
}

组合多个LiveData统一观察

当我们有多个LiveData时候,某些场景下我们想统一监听,那这个时候我们可以使用MediatorLiveData来对多个LiveData进行统一监听。

//创建两个长得差不多的LiveData对象
LiveData<Integer> liveData1 =  new MutableLiveData();
LiveData<Integer> liveData2 = new MutableLiveData();//再创建一个聚合类MediatorLiveDataMediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();//分别把上面创建LiveData 添加进来。
liveDataMerger.addSource(liveData1, observer);
liveDataMerger.addSource(liveData2, observer);Observer observer = new Observer<Integer>() {@Overridepublic void onChanged(@Nullable Integer s) {titleTextView.setText(s);}
//一旦liveData或liveData发送了新的数据 ,observer便能观察的到,以便  统一处理更新UI

转换数据

比如我们希望对一个Int值的LiveData在监听里变成String,那么我们可以用到Transformations.map 操作符进行该操作

MutableLiveData<Integer> data = new MutableLiveData<>();//数据转换
LiveData<String> transformData = Transformations.map(data, input ->   String.valueOf(input));
//使用转换后生成的transformData去观察数据
transformData.observe( this, output -> {});//使用原始的livedata发送数据
data.setValue(10);

LiveData实现原理

观察者生命周期

observe方法负责建立生命周期绑定关系,并注册观察者,如下所示:

@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);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;}owner.getLifecycle().addObserver(wrapper);}

LiveData将Observer对象加入mObservers中,数据变更时会遍历这个Map分发最新数据。LifecycleBoundObserver类负责监听应用组件的生命周期变化,如下所示:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();if (currentState == DESTROYED) {removeObserver(mObserver);return;}Lifecycle.State prevState = null;while (prevState != currentState) {prevState = currentState;activeStateChanged(shouldBeActive());currentState = mOwner.getLifecycle().getCurrentState();}}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}}

如onStateChanged方法所示,Lifecycle.State为DESTROYED时,移除观察者,其他情况则更改观察者的状态。

数据分发

有两个方法触发数据分发,一个是setValue,在数据变更时触发;一个是ObserverWrapper的activeStateChanged方法,在生命周期变更是触发(例如,从后台切换到前台),就是这个方法确保了应用组件的数据始终是最新的。如下所示:

private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = START_VERSION;ObserverWrapper(Observer<? super T> observer) {mObserver = observer;}void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;changeActiveCounter(mActive ? 1 : -1);if (mActive) {dispatchingValue(this);}}}@MainThreadprotected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}@SuppressWarnings("WeakerAccess") /* synthetic access */void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {considerNotify(initiator);initiator = null;} else {for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}@SuppressWarnings("unchecked")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;observer.mObserver.onChanged((T) mData);}

considerNotify方法负责实际的数据分发,如果观察者处于非激活态则不分发数据,否则有最新的数据就会分发到观察者,即调用onChanged((T) mData)方法。

本文主要讲解framework通信机制中的LiveData的用法以及原理,更多有关framework通信技术可以参考《framework全家桶手册》点击可查看详细内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/108439.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模型量化笔记--对称量化和非对称量化

1–量化映射 量化映射的通用公式为: r S ( q − Z ) r S(q - Z) rS(q−Z) 其中r表示量化前数据的真实值&#xff0c;S表示缩放因子&#xff0c;q表示量化后的数值&#xff0c;Z表示零点 2–非对称量化 非对称量化需要一个偏移量Z来完成零点的映射&#xff0c;即量化前的零…

pg嵌套子查询

1.概念 查询里面还有查询 进阶版&#xff1a;关联子查询 2.相关运算符补充 in/all/any all&#xff1a;表中的所有内容遍历一边&#xff0c;等价与max some/any&#xff1a;表中任何一个&#xff0c;等价与min

汉得欧洲x甄知科技 | 携手共拓全球化布局,助力出海中企数智化发展

HAND Europe 荣幸获得华为云颁发的 GrowCloud 合作伙伴奖项&#xff0c;进一步巩固了其在企业数字化领域的重要地位。于 2023 年 10 月 5 日&#xff0c;HAND Europe 参加了华为云荷比卢峰会&#xff0c;并因其在全球拓展方面的杰出贡献而荣获 GrowCloud 合作伙伴奖项的认可。 …

C++新经典 | C++ 查漏补缺(内存)

目录 一、new和delete 1.new类对象时&#xff0c;括号问题 2.new做了什么事 3.delete做了什么事 4.new与malloc的区别 5.delete与free的区别 二、分配及释放内存 三、重载operator new和operator delete操作符 1.重载类中的operator new和operator delete操作符 &…

vue+element实现电商商城礼品代发网,商品、订单管理

一、项目效果图 1.首页 2.登录 版本2&#xff1a; 3.注册 4.找回密码 5.立即下单 6.商品详情 7.个人中心-工作台 8.个人中心-订单列表 9.订单中心-包裹列表 10.个人中心-工单管理 11.我的钱包 12.实名认证 13.升级vip 14.个人中心-推广赚钱 二、关键源码 1.路由配置 impor…

【机器学习】PyTorch-MNIST-手写字识别

文章目录 前言完成效果一、下载数据集手动下载代码下载MNIST数据集&#xff1a; 二、 展示图片三、DataLoader数据加载器四、搭建神经网络五、 训练和测试第一次运行&#xff1a; 六、优化模型第二次优化后运行&#xff1a; 七、完整代码八、手写板实现输入识别功能 前言 注意…

vue重修【005】自定义路由、插槽

文章目录 版权声明自定义指令指令初识指令中配置项指令语法指令值v-loading指令的封装分析实现 插槽默认插槽插槽默认值具名插槽作用域插槽使用步骤完整案例 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程…

如何快速定位BUG?BUG定位技巧及测试人员定位的N板斧

很多测试人员可能会说&#xff0c;我的职责就是找到bug&#xff0c;至于找原因并修复&#xff0c;那是开发的事情&#xff0c;关我什么事&#xff1f; 好&#xff0c;我的回答是&#xff0c;如果您只想做一个测试人员最基本最本分的事情&#xff0c;那么可以这么想。但是&#…

微信批量发朋友圈,多个号同步

近年来&#xff0c;随着数字营销的飞速发展&#xff0c;越来越多的企业开始将客户引至微信&#xff0c;并通过群发广告和发布朋友圈等方式进行产品推广&#xff0c;以实现高效率、低成本和良好的转化效果。随着号多起来了&#xff0c;朋友圈推广工作变得愈发繁琐&#xff0c;需…

Vue3 + Nodejs 实战 ,文件上传项目--实现图片上传

目录 技术栈 1. 项目搭建前期工作(不算太详细) 前端 后端 2.配置基本的路由和静态页面 3.完成图片上传的页面&#xff08;imageUp&#xff09; 静态页面搭建 上传图片的接口 js逻辑 4.编写上传图片的接口 5.测试效果 结语 博客主页&#xff1a;専心_前端,javascript,mys…

TiDB 7.4 发版:正式兼容 MySQL 8.0

MySQL 是全球最受欢迎的开源数据库&#xff0c;长期位于 DB-Engines Ranking 排行榜第二名&#xff0c;在世界范围内拥有数量庞大的企业用户和开发者。然而&#xff0c;随着时间的推移&#xff0c;MySQL 用户正面临新挑战。Oracle 官宣将在 2023 年 10 月终止 MySQL 5.7 版本的…

2023,简历石沉大海?软件测试岗位真的已经饱和了....

各大互联网公司的接连裁员&#xff0c;政策限制的行业接连消失&#xff0c;让今年的求职雪上加霜&#xff0c;想躺平却没有资本&#xff0c;还有人说软件测试岗位饱和了&#xff0c;对此很多求职者深信不疑&#xff0c;因为投出去的简历回复的越来越少了。 另一面企业招人真的…

【halcon】halcon轮廓总结之select_contours_xld

前言 select_contours_xld 我认为是一个非常常用且实用的算子&#xff0c;用于对轮廓进行筛选。 简介 这段文档描述了一个名为"SelectContoursXld"的操作&#xff0c;用于根据不同特征选择XLD&#xff08;XLD是一种图像数据表示形式&#xff0c;表示轮廓线&#x…

竞赛 深度学习+python+opencv实现动物识别 - 图像识别

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

Golang学习:基础知识篇(二)—— 数组及切片

Golang学习&#xff1a;基础知识篇&#xff08;二&#xff09;—— 数组及切片 前言什么是Golang&#xff1f;Go语言的基础语法数组声明数组初始化数组访问数组知识点补充 切片定义切片切片初始化len() 和 cap() 函数空(nil)切片切片截取append() 和 copy() 函数知识点补充 前言…

ubuntu20.04安装FTP服务

安装 sudo apt-get install vsftpd# 设置开机启动并启动ftp服务 systemctl enable vsftpd systemctl start vsftpd#查看其运行状态 systemctl status vsftpd #重启服务 systemctl restart vsftpdftp用户 sudo useradd -d /home/ftp/ftptest -m ftptest sudo passwd ftptest…

使用 Python 和蒙特卡罗计算未来股价走势以及历史波动率和隐含波动率

一、简介 预测金融市场是定量精度和全球经济细微差别的复杂融合。在这一探索中,蒙特卡罗模拟脱颖而出,成为首要的统计工具,指导我们对未来股票价格的理解。 这种方法以摩纳哥著名的蒙特卡洛赌场命名,并不依靠运气,而是植根于严格的概率模型。想象一下在受控环境中精心策划…

vue3后台管理框架之技术栈

vue3全家桶技术 基础构建&#xff1a; vue3vite4TypeScript 代码格式 &#xff1a; eslintprettystylelint git生命周期钩子&#xff1a; husky css预处理器&#xff1a; sass ui库&#xff1a; element-plus 模拟数据: mock 网络请求&#xff1a; axios 路由&#xff1a; vue…

SAP MM学习笔记37 - 请求书照合中的 追加请求/追加Credit 等概念/ 请求书的取消

有关请求书照合&#xff0c;之前学习了一部分&#xff0c;现在再来学其中的一些概念。 其实这些概念也许并不常用&#xff0c;但是你又不能不知道&#xff0c;因为客户会问。 有关请求书&#xff0c;贴一些以前学习的文章&#xff0c;以方便阅读。 SAP MM学习笔记33 - 请求书…

38.迪杰斯特拉(Dijkstra)算法

概述 我们在上一篇中面对修路的问题讲述了普利姆算法的实现方式&#xff0c;本篇我们参照迪杰斯特拉算法来对修路问题做进一步拆解。 我们回顾一下之前的问题&#xff1a; “要想富&#xff0c;先修路”&#xff0c;郝乡长最近为了德胜乡修路的事情愁白了头。 得胜乡有A、B、C…