LiveData的原理和使用

article/2025/11/11 5:50:07

LiveData

Livedata是什么?它的作用是什么?我们能用它来干什么?

首先,LiveData是一种可观察的数据存储类。这句话可以看成两个部分,一个是可观察的类,另一个是数据存储的类。

  • LiveData 是可以被观察的, 但是与常规的可观察类不同,Livadata具有感知生命周期的能力。意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。有这种感知能力的LiveData ,只会通知活跃生命周期状态的应用组件观察者。
  • LiveData是用来存储数据的,这是它最直接的作用。当LiveData的数据发生变化的时候,就会通知应用组建的观察者。

Observe类的生命周期处于Start或者Resumed状态时候,LiveData就认为Observe类处于活跃状态。也就是说LiveData只会通知活跃的观察者,也就是说处于其他生命周期的观察者,即使LiveData发生了变化,也不会收到通知。这样的好处是避免了内存泄露。

LiveData的优势:

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

LIveData的使用:

  1. 创建LiveData实例,用来存储某种类型的数据。我们通常在ViewModel中完成。
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;public MutableLiveData<String> getCurrentName() {//有一个判空if (currentName == null) {currentName = new MutableLiveData<String>();}return currentName;}
// Rest of the ViewModel...
}
  1. 我们使用LiveData的方式主要有两种。
    • 一种是继承LiveData的子类MutableLIveData。因为LiveData是一个抽象类,我们不能直接继承,所以我们只能继承他的子类。
    • 一种是创建可定义 onChanged() 方法的 Observer 对象,该方法可以控制当 LiveData 对象存储的数据更改时会发生什么。通常情况下,您可以在界面控制器(如 activity 或 fragment)中创建 Observer 对象。
  2. 使用 observe() 方法将 Observer 对象附加到 LiveData 对象。observe() 方法会采用 LifecycleOwner 对象。这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,您可以在界面控制器(如 activity 或 fragment)中附加 Observer 对象。

LiveData的部分源码分析

MutableLiveData对外公开数据更新

LiveData的子类MutableLiveData,是我们可以直接使用的子类。在LiveData 里面没有公开的方法来更新存储的数据,但是在MutableLiveData中给我们提供了两个修改LiveData对象值的方法:setValue(T)和postValue(T)。同样这个两个方法也是重写了LiveData里面的方法。这两个方法分别适用在不同的线程里面。

package androidx.lifecycle;/*** {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.** @param <T> The type of data hold by this instance*/
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {/*** Creates a MutableLiveData initialized with the given {@code value}.** @param value initial value*/public MutableLiveData(T value) {super(value);}/*** Creates a MutableLiveData with no value assigned to it.*/public MutableLiveData() {super();}
/*** 如果有活动的观察者,值将被发送给他们。* @param value 新值* 只能在主线程调用*/@Overridepublic void postValue(T value) {super.postValue(value);}
/*** 如果有活动的观察者,值将被发送给他们。* @param value 新值* 只能在子线程调用*/@Overridepublic void setValue(T value) {super.setValue(value);}
}

observe订阅源码分析

obeserve订阅有两个方法。一个感知生命周期observe(),一个不感知生命周期observeForever()。

注册observe的方法需要传入两个参数,分别是生命周期的拥有者(一般是Activity、Fragment、Service)接收事件的观察者。

@MainThread
public 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);
}

下面我们逐句分析:

  1. 这个方法执行必须在主线程,否则抛出异常。
  2. 生命周期的拥有者不能是destoryed状态,否则结束方法。或者说忽视订阅请求
  3. 对生命周期的拥有者lifecycleOwner和事件的观察者observer进行包装注册成一个LifecycleBoundObserver对象,这就是为什么LiveData能够感知生命周期的原因。
  4. 封包和观察者必须是对应的,一个观察者不能同时观察多个生命周期。但是一个生命周期可以绑定多个观察者
  5. 添加观察者,这里可以很清楚的看到,添加的观察者是wrapper,而不是我们传入的observer参数。
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {assertMainThread("observeForever");AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {throw new IllegalArgumentException("Cannot add the same observer"+ " with different lifecycles");}if (existing != null) {return;}wrapper.activeStateChanged(true);
}

结论:这个方法创建的观察者,会永远收到数据变化的回调,在组件销毁时,需要用户手动的removObserver()。

逐句分析:

  1. 这里我们只传入了我们想设定的observer。没有传入生命周期的拥有者。

  2. 将observer包装成AlwaysActiviteObserver实例。同样wrapper和observer是对应的,如果已经添加到了LIveData,那么就抛出异常。

  3. activeStateChanged()方法传入true。将观察者立刻设置成活动态。它会一直保持在活动态,这就是他一直收到数据变化回调的秘诀。

observe移除源码

LiveData提供的observe移除方法也有两种,一种是移除removeObserve()方法传入的观察者。另一种是移除removeObserve()方法传入的生命周期拥有者,这样就会直接移除该生命周期所有绑定的观察者。

public void removeObserver(@NonNull final Observer<? super T> observer) {assertMainThread("removeObserver");ObserverWrapper removed = mObservers.remove(observer);if (removed == null) {return;}removed.detachObserver();removed.activeStateChanged(false);
}

源码分析:

  1. 判断主线程
  2. 分离观察者和生命周期拥有者
  3. 将观察者的一直设置成不活动态。
@SuppressWarnings("WeakerAccess")
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {assertMainThread("removeObservers");for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {if (entry.getValue().isAttachedTo(owner)) {removeObserver(entry.getKey());}}
}

这里明显进行了一次遍历,逐一调用移除单个Observe的方法。

LIfecycleBoundObserverl 类 和 AlwaysActiveObserver 类

这两个类就是上面我们包装形成wrapper,他们都继承了ObserWrapper。

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}
//活动态,返回true@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}activeStateChanged(shouldBeActive());}
//判断当前的owner是绑定的owner@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}
//分离观察者和生命周期拥有者@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}
}

LifecycleBoundObserver类里面的方法都是继承ObserverWrapper抽象类或者实现GenericLifecycleObserver接口的方法。实现GenericLifecycleObserver的onStateChanged()方法是LiveData能够观察生命周期的原因,而且使用LiveData不会发生内存泄露,当生命周期处于destoryed状态时候,会移除Observe。

private class AlwaysActiveObserver extends ObserverWrapper {AlwaysActiveObserver(Observer<? super T> observer) {super(observer);}
//这里默认返回true,观察者一直收到回调@Overrideboolean shouldBeActive() {return true;}
}

LiveData里面的postValue 和 setValue分析

这两个方法是用来更新数据的,使用postValue 和 setValue传递数据,在onChange()方法里面传入数据参数,进行更新。

//子线程
protected void postValue(T value) {boolean postTask;synchronized (mDataLock) {postTask = mPendingData == NOT_SET;mPendingData = value;}if (!postTask) {return;}ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

我没有贴全部的代码。ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);很显然这个是把数据又传递回主线程,在主线程中,又会调用setValue()方法。

//主线程
@MainThread
protected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);
}

主线程检查,赋值,分发的操作,主要的逻辑在dispatchingValue()方法中。

private volatile Object mData = NOT_SET;

这里需要提一个很重要的变量mData,存放数据的变量,可以看到它可以接受Object类型的数据,而且他是volatile类型,对于这个类型的变量,编译器会直接从原始的内存地址进行存取。

@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// mDispatchingValue的判断主要是为了解决并发调用dispatchingValue的情况
// 当对应数据的观察者在执行的过程中, 如有新的数据变更, 则不会再次通知到观察者。所以观察者内的执行不应进行耗时工作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);mDispatching

确实很复杂,但是我们只需要理解它最终是调用了considerNotify()方法来分发我们的mData。

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;}//检查版本号//每次setValue,version都会加一,当它超过我们的预设版本后,直接返回,防止我们多次调用onChange方法。if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;//noinspection uncheckedobserver.mObserver.onChanged((T) mData);
}

当上面的onChange()方法相当眼熟啊!这里收到了mData变量。

自定义LiveData时候会使用的方法:

void onActive () Called when the number of active observers change to
1 from 0. This callback can be used to know that this LiveData is
being used thus should be kept up to date.

当这个方法被调用时,表示LiveData的观察者数量从0变为了1,这时就我们的位置监听来说,就应该注册我们的时间监听了。

void onInactive () Called when the number of active observers change
from 1 to 0. This does not mean that there are no observers left,
there may still be observers but their lifecycle states aren’t STARTED
or RESUMED (like an Activity in the back stack). You can check if
there are observers via hasObservers().

这个方法被调用时,表示LiveData的观察者数量变为了0,既然没有了观察者,也就没有理由再做监听,此时我们就应该将位置监听移除

LiveData 数据监听机制流程图

img


http://chatgpt.dhexx.cn/article/xuFUrORa.shtml

相关文章

python电子书合集

Python电子书合集 小编最早接触的编程语言是C&#xff0c;决心走上编程之路的是JavaScript&#xff0c;后来入职靠的Java&#xff0c;后来发现还有一门短小精悍的语言叫——Python。 本来以为是一门新语言&#xff0c;结果才发现是自己out了&#xff0c;没想到这门语言比小编还…

《Python Cookbook》(中文第三版):电子书

《Python Cookbook&#xff08;第3版&#xff09;中文版》介绍了Python应用在各个领域中的一些使用技巧和方法&#xff0c;其主题涵盖了数据结构和算法&#xff0c;字符串和文本&#xff0c;数字、日期和时间&#xff0c;迭代器和生成器&#xff0c;文件和I/O&#xff0c;数据编…

python编程入门电子书-《Python编程 从入门到实践》高清电子书免费下载

今天给大家分享一本书 获取方式 公众号后台回复 Python基础 获取百度网盘下载链接 书籍简介 本书旨在让你成为优秀的程序员&#xff0c;具体地说&#xff0c;是优秀的Python程序员。通过阅读本书&#xff0c;你将迅速掌握编程概念&#xff0c;打下坚实的基础&#xff0c;并…

【小沐学Python】Python实现在线电子书制作(MkDocs + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建新项目4、添加页面5、编辑导航页6、设置主题7、更改图标图标8、构建网站9、部署9.1 准备github项目9.2 注册登录Read the Docs9.3 导入github项目到 Read the Docs 10、Markdown语法10.1 横线10.2 标题10.3 段落10.4 文字高亮10.5 换行10.6 斜体…

超全的Python完全版电子书——从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单的…

【小沐学Python】Python实现在线电子书制作(Sphinx + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建测试工程4、项目文件结构5、编译为本地文件6、编译为http服务7、更改样式主题8、支持markdown9、修改文档显示结构10、项目托管到github11、部署到ReadtheDocs结语 1、简介 Sphinx 是一个 文档生成器 &#xff0c;您也可以把它看成一种工具&…

python编程入门电子书-Python3零基础教材电子书合集

Python3零基础教材电子书合集&#xff0c;传送门&#xff1a;https://www.52pojie.cn/thread-676318-1-1.html 一、《Python编程从入门到实践》 链接&#xff1a;https://pan.baidu.com/s/1o9wJq0y 密码&#xff1a;12od 这书楼主现在也在看&#xff0c;讲的很细&#xff0c;…

学习Python必看的经典书籍(附电子书)

哈喽&#xff0c;我是牙儿 今天给大家推荐几本经典的Python书籍 一起来看看都有哪些吧~ 1 《Python学习手册&#xff08;第4版&#xff09;》 这本书全面、深入地介绍了 Python 语言&#xff0c;不管你是编程新手还是 Python 初学者&#xff0c;它将帮助你快速实现使用 Pyt…

超全的Python完全版电子书.pdf !从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单…

python入门经典电子书-推荐6本学习Python的免费电子书

便宜并不是没好货&#xff0c;这里的一些书籍已经被很多大学作为课本来使用&#xff0c;比如麻省理工的计算机科学与编程入门课程&#xff0c;加利福尼亚大学的编程思想课程都用到了下面的某(几)本书籍。 简明 简明 Python 教程是Swaroop C.H. 教授为Python初学者写的一本书。…

Python 开源电子书资源

转载自公众号&#xff1a;Mocun6 昨天给大伙儿送了书&#xff0c;留言区的篇幅占了整篇文章的一半&#xff0c;看来大家都想好&#xff08;把&#xff09;好&#xff08;我&#xff09;学&#xff08;掏&#xff09;习&#xff08;空&#xff09;。今天不送纸质书了&#xff0c…

100多本python书,免费电子版下载

推荐&#xff1a; 1、Coffee Break Python Slicing: 24 Workouts to Master Slicing in Python, Once and for All 切片&#xff08;Slicing&#xff09;是 Python 里非常有用的一个功能&#xff0c;属于 Python 开发人员最基本的技能之一。 如果你是初学者而且想了解 Slicin…

学习 Python 必看的书单(附电子书链接)

本文为你分享入门Python的必读书单。 学 Python 看什么书&#xff1f; 这是刚接触 Python 的朋友最疑惑的问题。 今天就结合自己入门时的学习历程和大家来聊一聊如何入门 Python&#xff0c;为了更有说服性一些&#xff0c;这里我把入门时看过的一些大佬推荐的书单进行了汇总…

python入门电子版-Python3零基础教材电子书合集

Python3零基础教材电子书合集,传送门:https://www.52pojie.cn/thread-676318-1-1.html 一、《Python编程从入门到实践》 链接:https://pan.baidu.com/s/1o9wJq0y 密码:12od 这书楼主现在也在看,讲的很细,建议大家零基础的从这书开始最好。个人觉得比《简明python教程》…

Python爬虫获取电子书资源实战

最近在学习Python&#xff0c;相对java来说python简单易学、语法简单&#xff0c;工具丰富&#xff0c;开箱即用&#xff0c;适用面广做全栈开发那是极好的&#xff0c;对于小型应用的开发&#xff0c;虽然运行效率慢点&#xff0c;但开发效率极高。大大提高了咱们的生产力。为…

全套Python零基础学习资料,电子书整理好了,想要进行技术提升,转行的自取!

今天分享Python入门级宝典 所有资料都是专业大佬总结整理出来的 Python的知识体系&#xff0c;从0开始学习Python看这一篇就够了! 《Python入门思维导图》 《看漫画学Python电子版》 《Python学习路线图》 《100道Python练习题》 《70个Python项目》 今天把这些分享给真…

【MATLAB统计分析与应用100例】案例015:matlab读取Excel数据,进行值聚类分析

1. 聚类分析轮廓图 2. matlab完整代码 %*****计算例9.1的距离矩阵 x = [1, 2, 6, 8, 11];

Python使用K-means聚类分析

Python使用K-means聚类分析 文章目录 Python使用K-means聚类分析介绍1.集群标签作为特征 一、k-均值聚类二、示例 - 加州住房2.KMeans 总结 介绍 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 本文将使用所谓的无监督学习算法。 无监督算法不使用目标&…

机器学习算法精讲20篇(一)-k-means聚类算法应用案例(附示例代码)

前言 k-means算法是非监督聚类最常用的一种方法,因其算法简单和很好的适用于大样本数据,广泛应用于不同领域,本文详细总结了k-means聚类算法原理 。 以下是我为大家准备的几个精品专栏,喜欢的小伙伴可自行订阅,你的支持就是我不断更新的动力哟! MATLAB-30天带你从入门…

【MATLAB统计分析与应用100例】案例016:matlab读取Excel数据,进行样品系统聚类分析

1. 聚类分析结果 2. matlab完整代码 (1)读取数据,并进行标准化 [X,textdata] = xlsread(examp09_02.xls); % 从Excel文件中读取数据 X = zscore(X