Android Jetpack之LiveData源码分析

news2024/11/17 9:28:07

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;
    //使用LiveData
    private MutableLiveData<String> contentLiveData = new MutableLiveData<>();

    @Override
    protected 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<String>() {
            @Override
            public void onChanged(String s) {
                mTextContent.setText(s);
            }
        });
        //点击按钮,改变内容
        findViewById(R.id.btn_livedata_change).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                contentLiveData.setValue("内容改变了");
            }
        });
    }
}


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

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

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

一、设置observe()方法

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

下面看下源码


    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
		...
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");

		//owner是Activity已经实现的(Lifecycle文章有说)
		//如果owner的生命周期已经结束的话,直接返回。避免了内存泄露,甚至Crash
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
		//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<T> extends LiveData<T> {

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}


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

    @MainThread
    protected 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。所以,走else
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
				//把所有观察者的Map,通过迭代器遍历
                for (Iterator<Map.Entry<Observer<? super T>, 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 解决方案

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

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

相关文章

DeFi:解决 EIP-4626 中的滑点问题

DeFi&#xff1a;解决 EIP-4626 中的滑点问题 简介 EIP-4626提供了一种将代币投资到投资池(通常称为金库)的标准方法。当我们存入自己的资产&#xff08;ERC-20 代币&#xff09;时&#xff0c;我们会收到一个份额代币&#xff0c;代表我们在金库里的资产。金库将把汇集的资产…

力扣 234. 回文链表

力扣 234. 回文链表 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&#xff1a; 输入&…

快速排序算法 QuickSort algorithm

该算法是托尼霍尔在1960年提出。 算法思想&#xff1a;从集合中随机取一个数作为支点&#xff0c;然后将比它大的数放在一个集合里&#xff0c;比它小的数放在另一个集合中&#xff0c;然后再递归下去&#xff0c;最后便可求得有序的数组。 QuickSort(A) 1: S− {}; S {}; …

LeetCode栈和队列练习

文章目录前言1.力扣20. 有效的括号1.题目分析2.代码示现2.力扣225. 用队列实现栈1.题目分析2.代码实现3.力扣232. 用栈实现队列1.题目分析2.代码实现4.力扣622. 设计循环队列1.题目分析2.代码实现5.总结前言 之前的博客介绍的栈和队列的实现&#xff0c;本文将会对栈和队列的使…

Unity - Shader - Projector 高空云层底下透明阴影

Semitransparent Shadow - Alpha Test SoftShadow 这种方式我最早是在 cat like coding 博主的文章看到的&#xff0c;这种方式我自己亲自测试过 缺点&#xff1a;会有阴影抖动严重的现象 &#xff08;其中的 dithering tex 可以参考我之前写的&#xff1a;Unity - 手动创建…

【图神经网络论文整理】(六)—— Universal Graph Transformer Self-Attention Networks

Dai Quoc Nguyen, Tu Dinh Nguyen, Dinh PhungThe ACM Web Conference 2022 (WWW 22)Computer Vision and Pattern Recognition论文地址 本文介绍的论文是《Universal Graph Transformer Self-Attention Networks》。 该篇文章的主要贡献是将Transformer应用在GNN中用于学习图…

Java Spring Bean的实例化

Java Spring Bean的实例化 Spring框架支持两种方式去进行Bean的管理&#xff1a;BeanFactory、ApplicationContext BeanFactory&#xff1a;pom文件引入spring-context坐标&#xff0c;创建对应的待IOC类&#xff0c;然后在bean.xml注入&#xff0c;最后在调用处初始化BeanFa…

【数据结构】树与二叉树

目录 树的定义 二叉树的定义 二叉树的性质 满二叉树 完全二叉树 二叉树的存储结构 顺序存储结构 链式存储结构 遍历二叉树&#xff08;递归&#xff09; 二叉树的层次遍历 先序创建二叉树 复制二叉树 销毁二叉树 写在最后 树的定义 树是n个结点的有限集&#xf…

微信小程序中生成普通二维码,并根据二维码里的参数跳转对应的页面

微信小程序中生成普通二维码&#xff0c;并根据二维码里的参数跳转对应的页面1.打开[微信公众平台](https://mp.weixin.qq.com/)使用encodeURIComponent()对参数进行转码第一步&#xff1a;对要传递的参数进行编码第二步&#xff1a;生成二维码第三步&#xff1a;小程序中转页面…

电子元器件B2B电商平台建设方案:优化企业商流,拓宽B2B交易渠道

随着5G、汽车电子、物联网等新兴产业的发展&#xff0c;促进了相关电子元器件的市场需求快速增长。根据工信部预计&#xff0c;2023年我国电子元器件销售总额将达到2.1万亿元。而在互联网高速发展的今天&#xff0c;电子元器件交易在线化是必然趋势&#xff0c;B2B电子元器件线…

maven学习:引入

你是否早已厌倦了日复一日的手工构建工作&#xff1f;你是否对各个项目风格迥异的构建系统感到恐惧&#xff1f;Maven——Maven 的正确发音是[ˈmevən]&#xff0c;而不是“马瘟”以及其他什么瘟。Maven 在美国是一个口语化的词语&#xff0c;代表专家、内行的意思。这一Java社…

自回归滞后模型进行多变量时间序列预测

下图显示了关于不同类型葡萄酒销量的月度多元时间序列。每种葡萄酒类型都是时间序列中的一个变量。 假设要预测其中一个变量。比如&#xff0c;sparkling wine。如何建立一个模型来进行预测呢&#xff1f; 一种常见的方法是将该变量其视为单变量时间序列。这样就有很多方法可以…

【从零开始学微服务】04.微服务架构的特点

大家好&#xff0c;欢迎来到万猫学社&#xff0c;跟我一起学&#xff0c;你也能成为微服务专家。 微服务架构被技术大牛们总结出了以下九个特点&#xff1a; 服务组件化围绕业务功能产品而不是项目强终端弱管道去中心化管理去中心化数据管理基础设施自动化容错性设计演进式设计…

Python 快速入门

文章目录Python 快速入门1 环境配置1.1 简介1.2 Python 安装1.3 其余软件1.4 编辑器的使用2 基础语法2.1 特点2.2 代码块2.3 注释3 数据类型3.1 变量类型3.2 数据结构3.3 运算符3.3.1 逻辑运算符3.3.2 比较运算符3.3.3 算术运算符3.3.4 布尔运算符4 流程语句4.1 循环语句4.1.1 …

Android App网络通信中通过okhttp调用HTTP接口讲解及实战(包括GET、表单格式POST、JSON格式POST 附源码)

需要全部源码或运行有问题请点赞关注收藏后评论区留言~~~ 一、通过okhttp调用HTTP接口 尽管使用HttpURLConnection能够实现大多数的网络访问操作&#xff0c;但是操作过于繁琐&#xff0c;于是Andorid从9.0是使用okhttp这个框架 由于okhttp属于第三方框架 所以使用前要修改模…

我们的程序是如何跑起来的?

1.我们写的代码写完并测试以后是如何部署给用户使用的? 1. 准备所需要的服务器 2. 在服务器上安装JDK、mysql、redis、Tomcat、Nginx等环境 3. 进行mysql、redis、nginx的连接配置 4. 项目打包。前端构建打包成功后在根目录dist文件夹中&#xff1b;后端打成jar包&#xff0c…

基于改进海洋捕食者算法求解单目标优化问题附matlab代码(NMPA)

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

VLAN网络支持ipv6的交换机和虚机配置

VLAN支持ipv6的交换机和虚机配置前言一、创建VLAN网络并配置交换机1.规划并在OpenStack上创建 VLAN网络2.在交换机上配置VLAN二、Ubuntu虚机配置1.创建虚机2.在OpenStack上查看port3.登录虚机配置网卡3.1登录虚机后&#xff0c;发现虚机没获取到openstack上对应port的ipv6地址。…

Qt编写跨平台视频监控系统(64通道占用7%CPU/支持win_linux_mac等)

一、前言 视频监控组件经历过数十年的迭代&#xff0c;从最初的只简单播放个rtsp视频流&#xff0c;到现在支持各种音频视频文件格式&#xff08;mp3、wav、mp4、asf、rm、rmvb、mkv等&#xff09;、支持各种视频流格式&#xff08;rtp、rtsp、rtmp、http等&#xff09;、支持…

10个JavaScript常见高级知识点

今天&#xff0c;给大家分享的是一篇干货知识《10个JavaScript常见高级知识点》&#xff0c;主要针对初级前端和想要面试找工作的同学&#xff0c;想要学好前端&#xff0c;除了要掌握JavaScript的基础知识外&#xff0c;还需要掌握一些高级的知识点。 学会了下面这些常见的高…