当前位置: 首页 > article >正文

Android jetpack LiveData (二) 原理篇

Android jetpack LiveData二原理篇引言源码前置分析核心类源码第一步定义LiveData对象第二步观察LiveData数据第三步 设置LiveData数据到这里我们先总结下黏性数据的步骤小结引言上一篇我们学习了LifeCycle的简单使用Android jetpack LiveData一使用篇那在这一篇主要学习LiveData的原理。源码前置分析核心类LiveData抽象类定义了 LiveData 的基本行为和接口。MutableLiveDataLiveData 的子类提供了 setValue 和 postValue 方法用于更新数据。Observer观察者接口用于定义数据更新时的回调方法。LifecycleBoundObserver实现了 Observer 接口并且具有生命周期感知能力确保只在合适的生命周期状态下通知观察者。LiveData.java定义了基本的数据观察和设置方法。publicabstractclassLiveDataT{MainThreadpublicvoidobserve(NonNullLifecycleOwner owner,NonNullObserver?superTobserver){...}MainThreadpublicvoidobserveForever(NonNullObserver?superTobserver){...}protectedvoidpostValue(T value){...}MainThreadprotectedvoidsetValue(T value){...}protectedvoidonActive(){}protectedvoidonInactive(){}}MutableLiveData.javaLiveData的子类publicclassMutableLiveDataTextends LiveDataT{OverridepublicvoidpostValue(T value){super.postValue(value);}OverridepublicvoidsetValue(T value){super.setValue(value);}}源码我们按照使用的顺序来进行源码分析第一步定义LiveData对象publicMutableLiveData(){super();}在核心类里面了解到MutableLiveData是LiveData的子类所以我们去LiveData中看定义。在这里进行数据对象初始化。publicabstractclassLiveDataT{publicLiveData(T value){mDatavalue;mVersionSTART_VERSION1;}publicLiveData(){// 逻辑走这里mDataNOT_SET;mVersionSTART_VERSION;// -1 (初始为-1 哦后面会用到)}}第二步观察LiveData数据这个observe方法同样进入LiveData.java类中分析。MainThreadpublicvoidobserve(NonNullLifecycleOwner owner,NonNullObserver?superTobserver){// 1assertMainThread(observe);if(owner.getLifecycle().getCurrentState()DESTROYED){// 2return;}// 3LifecycleBoundObserver wrappernewLifecycleBoundObserver(owner,observer);ObserverWrapper existingmObservers.putIfAbsent(observer,wrapper);if(existing!null!existing.isAttachedTo(owner)){thrownewIllegalArgumentException(Cannot add the same observer with different lifecycles);}if(existing!null){return;}// 4owner.getLifecycle().addObserver(wrapper);}MainThreadpublicvoidobserveForever(NonNullObserver?superTobserver){assertMainThread(observeForever);AlwaysActiveObserver wrappernewAlwaysActiveObserver(observer);ObserverWrapper existingmObservers.putIfAbsent(observer,wrapper);if(existing instanceof LiveData.LifecycleBoundObserver){thrownewIllegalArgumentException(Cannot add the same observer with different lifecycles);}if(existing!null){return;}wrapper.activeStateChanged(true);}这里我贴出了两个观察方法。observe方法不需要自己手动清理观察者,当LifecycleOwner进入DESTROYED状态时会自动移除观察者。下面这个observeForever会一直观察不需要传入lifecycleOwner,但是需要自己在不用时销毁removeObserver。// 1第一步要验证这个方法是否在主线程证明该方法必须要在主线程调用。否则会抛出异常崩溃// 2第二步是判断当LifecycleOwner进入DESTROYED状态时自动移除观察者。这个owner就是我们调用该方法时传入的owner;// 3第三步出现了新的观察类LifecycleBoundObserver可以看到它实现了LifecycleEventObserver这个在我们学习Lifecycle的时候有讲过主要是通过onStateChanged来观察生命周期可以看下面的代码。// 4核心。owner.getLifecycle().addObserver(wrapper);兜兜转转又回到了Lifecycle里面把这个观察者添加到lifecycle里面。之前在Lifycycle原理篇有讲过为lifycycle添加观察者等lifecycleowner的生命周期变化就会出发lifecycle event事件。classLifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver{NonNullfinalLifecycleOwner mOwner;LifecycleBoundObserver(NonNullLifecycleOwner owner,Observer?superTobserver){super(observer);mOwnerowner;}OverridebooleanshouldBeActive(){returnmOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}OverridepublicvoidonStateChanged(NonNullLifecycleOwner source,NonNullLifecycle.Event event){Lifecycle.State currentStatemOwner.getLifecycle().getCurrentState();if(currentStateDESTROYED){removeObserver(mObserver);return;}Lifecycle.State prevStatenull;while(prevState!currentState){prevStatecurrentState;activeStateChanged(shouldBeActive());currentStatemOwner.getLifecycle().getCurrentState();}}OverridebooleanisAttachedTo(LifecycleOwner owner){returnmOwnerowner;}OverridevoiddetachObserver(){mOwner.getLifecycle().removeObserver(this);}}接着往下看这个代码activeStateChanged(shouldBeActive());能看到当前状态是active的时候会分发数据dispatchingValue(this);voidactiveStateChanged(boolean newActive){if(newActivemActive){return;}// immediately set active state, so wed never dispatch anything to inactive// ownermActivenewActive;changeActiveCounter(mActive?1:-1);if(mActive){dispatchingValue(this);}}dispatchingValue在LiveData中这个方法用于将最新的值分发给观察者。voiddispatchingValue(NullableObserverWrapper initiator){// 首先检查是否正在分发值mDispatchingValue为true。// 如果是则设置mDispatchInvalidated true并立即返回。// 这意味着如果有递归调用它会标记当前分发无效让外层循环知道需要重新执行。if(mDispatchingValue){mDispatchInvalidatedtrue;return;}mDispatchingValuetrue;do{mDispatchInvalidatedfalse;if(initiator!null){considerNotify(initiator);initiatornull;}else{for(IteratorMap.EntryObserver?superT,ObserverWrapperiteratormObservers.iteratorWithAdditions();iterator.hasNext();){considerNotify(iterator.next().getValue());//循环结束后检查mDispatchInvalidated标志。// 如果为true表示在分发过程中发生了无效化//通常是因为有新的数据变化导致需要重新分发那么循环会再次执行//重新开始分发。否则退出循环。if(mDispatchInvalidated){break;}}}}while(mDispatchInvalidated);mDispatchingValuefalse;// 分发结束}上述核心方法considerNotify(initiator);considerNotify是 LiveData 中实际触发观察者回调的关键方法它在dispatchingValue中被调用用于向单个观察者派发数据。observer.mObserver.onChanged((T) mData);确保只有在观察者处于正确状态且数据确实更新时才通知同时维持了与 Lifecycle 组件的生命周期安全集成。privatevoidconsiderNotify(ObserverWrapper observer){if(!observer.mActive){return;}if(!observer.shouldBeActive()){observer.activeStateChanged(false);return;}if(observer.mLastVersionmVersion){// 这块是来判断黏性数据的return;}observer.mLastVersionmVersion;observer.mObserver.onChanged((T)mData);}这里最后就是我们回调的onChanged方法那我们通过上面的分析就知道livedata通过注册lifecycle观察者在事件变更时能接收到变化。接下来我们继续看第三步第三步 设置LiveData数据使用setValue主线程/postValue子线程的形式去设置Livedata数据因为postValue最终也会调用到setValue,所以我们从postValue()看起protectedvoidpostValue(T value){boolean postTask;// 加同步锁考虑线程安全synchronized(mDataLock){postTaskmPendingDataNOT_SET;mPendingDatavalue;}if(!postTask){return;}// 在这里线程切换到主线程ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}privatefinalRunnable mPostValueRunnablenewRunnable(){SuppressWarnings(unchecked)Overridepublicvoidrun(){Object newValue;synchronized(mDataLock){newValuemPendingData;mPendingDataNOT_SET;}setValue((T)newValue);}};看上述代码看到在postValue()中将线程切换到主线程中在主线程中又调用了setValue()。至此我们就知道postValue最终也会通过runnable调用到setValue().MainThreadprotectedvoidsetValue(T value){assertMainThread(setValue);mVersion;// 首次-1 - 0mDatavalue;dispatchingValue(null);// null进入for循环加到观察者里}可以看到上面的setValue是必须要在主线程中调用的。如果在子线程调用会抛出异常。接着往下看。mVersion,此时首次进入这个值从-1变成了0同时传入wrapper是null(这个方法我们再第二步中也有描述)voiddispatchingValue(NullableObserverWrapper initiator){if(mDispatchingValue){mDispatchInvalidatedtrue;return;}mDispatchingValuetrue;do{mDispatchInvalidatedfalse;if(initiator!null){considerNotify(initiator);initiatornull;}else{for(IteratorMap.EntryObserver?superT,ObserverWrapperiteratormObservers.iteratorWithAdditions();iterator.hasNext();){considerNotify(iterator.next().getValue());if(mDispatchInvalidated){break;}}}}while(mDispatchInvalidated);mDispatchingValuefalse;}首次mObservers可以有多个是一个map集合。因此进入for循环全部加进来。此时我们再去看considerNotify方法中的version// mLastVersion 为-1// mVersion为0没法进入这里往下走后续走传入的observer不为空的逻辑直接调用。if(initiator!null){considerNotify(initiator);initiatornull;}int mLastVersionSTART_VERSION;// -1privatevoidconsiderNotify(ObserverWrapper observer){if(!observer.mActive){return;}if(!observer.shouldBeActive()){observer.activeStateChanged(false);return;}// 不触发if(observer.mLastVersionmVersion){return;}observer.mLastVersionmVersion;// 直接把数据分发下去。这个数据在这里是指代的订阅之前接设置好的黏性数据哦后续就是订阅之后传入的数据了。observer.mObserver.onChanged((T)mData);}到这里我们先总结下黏性数据的步骤1、在订阅之前先设置好valueliveData.value 202、mVersion 变为03、将设置的value传入mDatamData value;也就是mData 20埋下伏笔4、接着我们订阅观察者。在LifecycleBoundObserver中当我们的owener启动生命周期变化后会通过activeStateChange分发当前数据见下图这里就不走循环了不需要再把observer加到map集合了。5、后面就是considerNotify判断observer.mLastVersion mVersion.这里mLastVersion为-1mVersion在2中变成了0因此无法进入判断。mLastVersion设置为0同时触发我们观察者的onChanged((T) mData)。这里的mData就是什么没错就是那个在1中设置好的数据20小结可以用这张图来表示。下一步可能会讲讲怎么解决数据倒灌黏性数据。ing…

相关文章:

Android jetpack LiveData (二) 原理篇

Android jetpack LiveData(二)原理篇引言源码前置分析核心类源码第一步,定义LiveData对象第二步,观察LiveData数据第三步: 设置LiveData数据到这里我们先总结下黏性数据的步骤:小结引言 上一篇我们学习了L…...

【PCIe 验证每日学习・Day13】DLLP 与 ACK/NAK 重传机制基础验证

大家好,继续我们「PCIe 验证每日学习・30 分钟打卡」系列。今天进入数据链路层核心:DLLP 帧结构、ACK/NAK 应答机制与重传验证。内容严格遵循 PCIe 规范、100% 无错误,讲解通俗、结构清晰、代码可直接复用,风格与前几日完全统一&a…...

Linux 的 cat 命令

Linux 的 cat 命令详解 命令概述 cat(concatenate 的缩写)是 Linux 系统中最基础且常用的命令之一,主要用于查看文件内容、合并文件以及创建简单文件。该命令属于 GNU coreutils 包的一部分,几乎在所有 Linux 发行版中都默认安装…...

burpsuite详细安装教程及功能讲解

好久不见,各位道友 目录 好久不见,各位道友 Brp Suite 介绍 正常情况下(不使用Burp Suite),客户端与服务器的交互过程如下: 当加入Burp Suite时,客户端与服务器的交互过程如下:…...

春日桌搭新首选!ROG魔霸9 Mini:3L 迷你机身,塞下锐龙 9+RTX5070

三月春意渐浓,很多人都开始给自己的桌面焕新升级,而一款体积小巧、性能够强的主机,绝对是桌搭升级的核心。最近 ROG 推出的魔霸 9 Mini 电竞迷你主机,就精准命中了玩家与办公人群的核心需求 —— 仅 3L 的超小体积,却塞…...

Qt导航栏组件A03:VS Code 风格的图标侧栏

目录 一、引言 二、最终效果预览 三、核心实现原理 3.1 布局结构设计 3.2 核心技术点 四、代码实现详解 4.1 项目结构 4.2 导航组件的核心代码 4.3 样式表设计 五、总结 5.1 核心要点回顾 5.2 学习建议 源码下载 系列编号:A-03 导航风格:只有图标的侧栏 适用场景:IDE、编辑器…...

计算机毕业设计源码:Python贝壳租房数据可视化与智能推荐系统 Scrapy爬虫 可视化 推荐系统 大数据 数据分析 大模型 房源 房子(建议收藏)✅

博主介绍:✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久,选择我们就是选择放心、选择安心毕业✌ > 🍅想要获取完整文章或者源码,或者代做,拉到文章底部即可与…...

深度探索Fluent中的电弧、激光与熔滴一体化模拟

Fluent电弧,激光,熔滴一体模拟。 UDF包括高斯旋转体热源、双椭球热源(未使用)、VOF梯度计算、反冲压力、磁场力、表面张力,以及熔滴过渡所需的熔滴速度场、熔滴温度场和熔滴VOF。初识激光熔化沉积:一场材料…...

电-气-热综合能源系统节点能价计算方法研究

基本文献复现-计及碳排放成本的电_气_热综合能源系统节点能价计算方法研究 真正做到了电热气潮流耦合,很适合综合能源系统建模的初学者,配合复现论文。 运行程序HeatGasPowerCombination即可。 每个系统模型都有专门的文档讲解,程序注释齐全。…...

香草纪元开服教程:使用云鸢联机平台快速搭建“食旅纪行”服务器(高配推荐版)

你是否喜欢原版风格,热爱收集,渴望在minecraft中休闲养老?你是否喜欢眼前一亮的各种新奇模组,热爱探索,打造神器征战各种boss?你是否在找一个农夫乐事大型养老包,想在mc里做个美食家&#xff1f…...

增程式电动汽车自适应ECMS能量管理策略:基于工况的Matlab实现方案

增程式电动汽车基于工况的自适应ECMS能量管理策略(matlab的m程序) 最近试驾某品牌增程式电动车时,发现一个有趣现象:堵车时增程器几乎不启动,而上了高速却像开了狂暴模式。这背后的能量管理策略有点东西,今…...

Comsol锂枝晶模型:锂枝晶生长与锂离子浓度、电势分布的模拟

comsol锂枝晶模型 Comsol 锂枝晶生长模型,锂枝晶生长,锂离子浓度分布,电势分布 此链接是随机形核生长锂电池实验室里最让人头疼的玩意就是锂枝晶。这货像金属胡须一样野蛮生长,动不动就刺穿隔膜搞短路。去年用COMSOL建锂枝晶模型时…...

基于改进蛇优化算法(GOSO/ISO)优化极限梯度提升树的时间序列预测

基于改进蛇优化算法(GOSO/ISO)优化极限梯度提升树的时间序列预测(GOSO/ISO-XGBoost) 蛇优化算法SO是2022年提出的新算法,性能优异,目前应用较少,改进蛇优化算法GOSO/ISO应用更少,适合PAPER 改进点1为在初始化种群引入混沌映射&…...

大厂ZigBee射频芯片CC2430反向电路探索

大厂ZigBee射频芯片CC2430反向电路 学习方法是:可以直接查看里面的电路结构,还有管子的宽长比参数等。 拿到原理图之后需要自己换成自己所持有的PDK就可以跑仿真了,国内大部分公司都是这样设计芯片产品的,参考价值非常大&#xff…...

Matlab实现频率切片小波变换(FSWT)绘制时频图

Matlab进行频率切片小波变换(FSWT)源代码,将一维信号生成时频图。 输入信号可以是任何一维信号,心电信号、脑电信号、地震波形、电流电压数据等。 相比连续小波变换(CWT),频率切片小波变换(Frequency Slice Wavelet Transform,FSWT)是一种更具…...

Prompt工程深度揭秘

🎯 Prompt工程深度揭秘:AI的"说明书"是如何进化的 从简单指令到复杂工程:理解Prompt如何让AI变得"听话" 你是不是好奇,这些这么多的新东西,他们在使用的时候不都是一堆提示词嘛,那分裂…...

飞轮储能系统建模详解与MATLAB仿真实践(含永磁同步电机驱动模型)含多种模型与建模仿真指南

飞轮储能系统的建模与MATLAB仿真 飞轮储能系统的建模与MATLAB仿真(永磁同步电机作为飞轮驱动电机)含详细建模文件 内含两个飞轮储能模型:模型一的机侧网侧分开运行,附54页建模仿真说明;模型二的机侧网侧同步运行——内…...

基于全阶磁链观测器的异步电机矢量控制

基于全阶磁链观测器的异步电机矢量控制全阶磁链观测器的主要思想是将异步电机模型作为参考,把状态估计的方程作为可调节部分。 这两部分具有相同物理意义的输出量,利用两个部分的输出量误差再经过反馈校正通道对状态观测值进行修正,使观测值快…...

高级特性之dubbo超时机制及集群容错机制

当服务消费者要进行消费的时候,这个时候它可能就开启一个线程去调用服务提供者的具体实现,等他返回相应的结果,这个时候由于网络的问题或者服务端并不可靠,它会在这阻塞很长的一段时间。如果这个服务一直有人在调用那么就会开一堆…...

西门子S7-1200 PLC工业污水处理系统:基于博途V13sp1的WinCC画面组态与仿真报告

西门子工业污水处理系统,plc污水处理系统,基于plc的污水处理系统,系统采用s7-1200PLC设计,博途wincc画面组态。 包括plc触摸屏组态画面及仿真,报告等 博途V13sp1编程,V13sp1以上版本可以打开工业污水处理系…...

事件触发控制代码及其对应参考文献

事件触发控制代码对应参考文献 1.2023IEEE TRANS 顶刊基于事件触发的深度强化学习自动驾驶决策(CCF-A) 2.多智能体分布式系统的事件触发控制 3.基于观测器的非理想线性多智能体事件触发的跟踪一致性 4.非线性不确定扰动多智能体系统固定时间事件触发一致…...

实测对比后!千笔AI,开源免费降重首选

在AI技术迅速发展的今天,越来越多的学生和研究人员开始依赖AI工具辅助论文写作。然而,随着知网、维普、万方等查重系统不断升级算法,以及Turnitin对AIGC(人工智能生成内容)的识别愈发严格,AI率超标问题已成…...

直驱风机Simulink仿真模型与永磁直驱式风力发电系统整体仿真:380V与690V双电压仿真...

直驱风机simulink仿真模型,永磁直驱式风力发电系统 matlab/simulink整体仿真,有380V和690V两个仿真,波形如图,现货有2018 和 2021 两个版本,可导出2015b-2022版本,有模型说明和文献直驱风机在风电场的应用这…...

Canoe-Autosar网络管理自动化测试脚本及Capl源码:全套、可直接使用修改项目配置

Canoe-Autosar网络管理自动化测试脚本 Capl源码,全套,修改项目配置可以直接使用。 1.启动程序 2.加载配置文件 3.选择帧类型(标准帧或扩展帧) 4.修改配置文件,自动弹出配置文件窗口 5.选择测试用例 6.点击运行 7.测试完成打印报告并记录对应…...

基于LADRC自抗扰控制的VSG三相逆变器预同步并网策略

基于LADRC自抗扰控制的VSG三相逆变器预同步并网控制策略 基于LADRC自抗扰控制的VSG三相逆变器预同步并网控制策略是一种用于实现逆变器在微电网中的协调运行的先进控制策略。 逆变器控制方式采用虚拟同步发电机控制(VSG),通过引入虚拟同步发电…...

桥梁裂缝图像识别 智慧桥梁钢筋裸漏图像识别 基建领域混凝土结构病害检测 桥梁病害图像 YOLO格式数据集 第10515期

混凝土病害检测数据集 README类别 锈蚀钢筋 蟹爪状破损 碳化 受侵蚀混凝土 开裂混凝土 劣质混凝土 剥落 泛碱 微裂缝 裂缝往期热门主题 主页搜两字"关键词"直达 代码数据获取: 获取方式:***文章底部卡片扫码获取***覆盖了YOLO相关项目、OpenCV…...

基于FPGA的视频缩放算法:支持4K2K输入与输出,缩放参数可控

基于fpga的视频缩放算法,支持4k2k输入,4k2k输出,缩放参数可控。最近在折腾一个FPGA视频处理项目,发现市面上的缩放方案要么延迟太高,要么资源占用爆炸。自己动手撸了个支持4K60帧的缩放架构,参数还能实时调…...

【Day25】LeetCode:134. 加油站,135. 分发糖果,860. 柠檬水找零,406. 根据身高重建队列

文章目录LeetCode:134. 加油站思路解答LeetCode:135. 分发糖果思路解答LeetCode:860. 柠檬水找零思路解答LeetCode:406. 根据身高重建队列思路解答LeetCode:134. 加油站 https://leetcode.cn/problems/gas-station/ …...

Linux HTTP服务器

1.完成对于服务器的基础编写socket.hpp套接字模块#pragma once #include<iostream> #include <sys/types.h> #include <sys/socket.h> #include<string> #include<netinet/in.h> #include <arpa/inet.h>//sockaddr_in 头文件 #include&quo…...

进程优先级/进程切换

1.优先级的基本概念进程优先级决定CPU执行顺序&#xff0c;优先级高的进程优先获得CPU&#xff0c;合理配置优先级可提升系统性能可将进程绑定到特定CPU核心运行&#xff0c;把不重要进程隔离到某CPU&#xff0c;避免干扰核心任务&#xff0c;显著改善整体系统性能和资源利用效…...