LiveData使用和原理

LiveData使用和原理

本文链接:https://blog.csdn.net/feather_wch/article/details/131797422


文章目录

  • LiveData使用和原理
    • LiveData使用
      • Transformations
    • LiveData相关类
    • 原理
      • 粘性事件
      • 数据倒灌
    • 问题思考
      • 设计模式

要点:

  1. 注册监听+事件分发+生命周期感知
  2. 粘性事件

LiveData使用

1、LiveData不能在子线程putValue,只能postValue

object MyLiveData {val data:MutableLiveData by lazy { MutableLiveData() }init {data.value = "default" // 该单例第一次在子线程中使用,会触发初始化,putValue()会闪退// 另一个进程的Service中thread{}中去使用,会出现问题}
}

2、后观察数据是什么效果?为什么可以收到之前的数据?

  1. 会收到数据 => 【数据粘性】
  2. 一般动态修改LiveData源码,避免数据粘性

3、怎么修改数据粘性?

  1. Hook,反射,动态修改源码

4、LiveData简单使用

  1. 创建一个 LiveData 对象并提供一个初始值:
val data = MutableLiveData()
data.value = "Hello LiveData"
  1. 在观察者中订阅 LiveData 对象以接收数据的更新:
data.observe(this, Observer { value ->// 在这里处理数据更新的逻辑println(value)
})

5、在 ViewModel 中使用 LiveData:

class MyViewModel : ViewModel() {private val _data = MutableLiveData()val data: LiveData get() = _data // 将其转换为不可变的 LiveData 对象 `data`fun fetchData() {// 模拟从网络或数据库获取数据val newData = "New Data"_data.value = newData // Activity 或 Fragment 可以通过观察 `data` 来接收数据的更新。}
}

Transformations

6、使用 Transformations.map 转换 LiveData:Int->String

// 转换:添加内容返回新的LiveData对象
val data: LiveData = Transformations.map(sourceData) { input ->"Transformed: $input"
}

7、数据排序:当你从数据库或网络获取到未排序的数据列表时,你可以使用 Transformations.map 来将其排序成一个有序的列表:

val unsortedListLiveData: LiveData<List> = ...
val sortedListLiveData: LiveData<List> = Transformations.map(unsortedListLiveData) { unsortedList ->unsortedList.sorted()
}

、数据过滤:当你需要根据特定条件筛选出符合条件的数据时,你可以使用 Transformations.map 来进行数据过滤:

val originalLiveData: LiveData<List> = ...
val filteredLiveData: LiveData<List> = Transformations.map(originalLiveData) { originalList ->originalList.filter { it.startsWith("A") } // 只保留以字母 "A" 开头的元素
}

LiveData相关类

1、LiveData:

  1. LiveData 是一个抽象类,用于定义可观察的数据持有者。
  2. 它具有生命周期感知能力,可以自动保证数据更新时只在活跃的观察者中进行通知。

2、MutableLiveData:

  1. MutableLiveData 是 LiveData 的子类,可以更改持有的数据。
  2. 它提供了 setValue() 和 postValue() 方法,用于更新 LiveData 中的值。通常用于作为可观察的数据源。

3、MediatorLiveData:

  1. MediatorLiveData 是 MutableLiveData 的子类,可以合并多个 LiveData 对象,并在其中一个 LiveData 发生更改时通知观察者。

4、Transformations:

  1. Transformations 是一个工具类,提供了一些转换函数,用于对 LiveData 进行转换操作,如 map()、switchMap()、filter() 等。

5、Observer:

  1. Observer 是一个函数接口(SAM 接口-单个抽象方法),用于定义观察者的操作逻辑。
  2. 通常可以使用 lambda 表达式、匿名内部类或 ViewModel 中的引用来实现 Observer 接口。

6、LifecycleOwner:LifecycleOwner 是一个接口,表示具有生命周期感知能力的组件,如 Activity、Fragment。LiveData 可以感知 LifecycleOwner 的生命周期,自动管理观察者的注册和注销。

7、SAM单个抽象方法,类似有Runnable

public interface Observer {void onChanged(T t);
}

8、LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver

  1. 是LiveData内部的辅助类
  2. LifecycleOwner销毁时,取消订阅
  3. LifecycleOwner处于活动状态(STARTED和RESUMED)会调用onActive()告诉外界活动中
  4. LifecycleOwner处于非活动状态(STOPPED和DESTROYED),会调用onInactive()告诉外界非活动
  5. 可以避免浪费资源或内存泄漏。

原理

1、注册监听流程

MutableLiveData("String").observe(this){it}
#LiveData
observe(LifecycleOwner owner, Observer observer)->assertMainThread("observe");if (owner.getLifecycle().getCurrentState() == DESTROYED) return; // 1. 销毁,无反应,避免内存泄漏->LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);// 2. 包装成真正的观察者,去感知Lifecycle->ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);  // 3. SafeIterableMap,线程安全Map,不存在添加,存在则取出->owner.getLifecycle().addObserver(wrapper); // 4. 注册监听,生命周期

2、感知Lifecycle生命周期

  1. 生命周期改变–>判断–>dispatchingValue()分发数据
LifecycleBoundObserver.onStateChanged() 会感受到生命周期变化->DESTROYED => removeObserver(mObserver);->activeStateChanged(shouldBeActive());->dispatchingValue(ObserverWrapper)->for()遍历->considerNotify()->if (observer.mLastVersion >= mVersion) return; // 粘性事件->observer.mObserver.onChanged((T) mData); // 传输数据给观察者

3、事件分发:postValue、setValue

#LiveData
->assertMainThread("setValue");
->mVersion++; // 发一次事件,版本号+1
->mData = value;
->dispatchingValue(null);->for()遍历->considerNotify()->if (observer.mLastVersion >= mVersion) return; // 粘性事件->observer.mObserver.onChanged((T) mData); // 传输数据给观察者

粘性事件

4、observer.mLastVersion和mVersion

  1. mVersion:每次数据更新时++
  2. observer.mLastVersion表示上次观察者接收到的版本号。// = mVersion
  3. observer.mLastVersion >= mVersion:观察者已经接收过相同版本的数据,直接返回,避免重复处理相同的数据。

5、为什么会有粘性事件

  1. 新建观察者 mLastVersion = START_VERSION = -1
  2. 会收到LiveData的最新数据
  3. 不是BUG,默认有粘性,用户可以自主解决粘性问题

6、如何解决粘性事件

  1. 反射让observer.mLastVersion、mVersion相等
  2. UnPeekLiveData版本:自己模拟mVersion和Observer的mLastVersion,在onChanged()判断是否交给外界Observer。
  3. LiveData数据恢复时,也会恢复咱们自定义的mVersion,系统调用LiveData的observe()重新构建实例是用的是这个恢复后的mVersion作为模拟的mLastVersion
  4. 官方SingleLiveData:不支持多个观察者

数据倒灌

7、什么是数据倒灌?本质就是粘性事件,新造了名词。

  1. 下面总结:本质还是在LiveData有数据后,observe()会接收到上一次数据。
  2. Activity异常销毁然后重建,ViewModel中的Livedata会保存之前数据包括mVersion
  3. Activity重建后会调用LiveData的observe(),内部会重新new一个实例,会将mLastVersion恢复到初始值。
  4. observe()->addObserver()->注册生命周期监听,就会触发生命周期回调,就会分发事件dispatchingValue()判断版本号

问题思考

1、LiveData在多线程中是如何处理的?
2、为什么要有MutableLiveData而不是直接使用LiveData?体现了什么原则?

  1. 开闭原则
  2. LiveData内部非常庞大复杂,MutableLiveData对扩展开放,对修改关闭

设计模式

1、LiveData的模板方法模式:onActive、onInactive
2、外观模式:MutableLiveData隐藏了LiveData内部的复杂子系统,注册监听、生命周期感知、事件分发

自己实现KT版本LiveDataBusKt

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

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

相关文章

【springboot】RestTemplate的使用、格式转换、异常处理、拦截器,

RestTemplate提供了一个基于Http客户端库&#xff08;HttpClient&#xff0c;OkHttp等&#xff09;的高层次API&#xff0c;并不是重复制造轮子。 RestTemplate提供了常见的REST请求方案的模版&#xff0c;例如GET请求、POST请求、PUT请求、DELETE请求以及一些通用的请求执行方…

整数拆分(力扣)动态规划 JAVA

给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释: 10 3 3 4…

Python应用实例(二)数据可视化(二)

数据可视化&#xff08;二&#xff09; 1.随机漫步1.1 创建RandomWalk类1.2 选择方向1.3 绘制随机漫步图1.4 模拟多次随机漫步1.5 设置随机漫步图的样式 1.随机漫步 使用Python来生成随机漫步数据&#xff0c;再使用Matplotlib以引人瞩目的方式将这些数据呈现出来。随机漫步是…

使用 YOLOv8 和 Streamlit 构建实时对象检测和跟踪应用程序:第 1 部分-介绍和设置

示例:图像上的对象检测 介绍 实时视频中的目标检测和跟踪是计算机视觉的一个重要领域,在监控、汽车和机器人等各个领域都有广泛的应用。 由于需要能够识别和跟踪对象、确定其位置并对它们进行实时分类的自动化系统,对视频帧中的实时对象检测和跟踪的需求日益增加。 在这…

MinIO:开源对象存储解决方案

MinIO是一款开源的云原生对象存储解决方案&#xff0c;旨在提供高性能、可扩展和持久化存储服务。它兼容Amazon S3 API&#xff0c;可以轻松地集成到现有的应用程序中&#xff0c;为用户提供可靠的对象存储和数据管理。本文将介绍MinIO的基本概念、架构设计以及常见的应用场景&…

Java反射

Java中的字节码&#xff1a;Java源代码经过虚拟机编译器编译后产生的文件&#xff08;即扩展为.class的文件&#xff09;&#xff0c;它不面向任何特定的处理器&#xff0c;只面向虚拟机。 1.反射的定义 反射机制 JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&…

GitUI汉化

1.下载汉化文件 下载地址 备用下载地址 https://files.cnblogs.com/files/chenghu/git-gui-zh-master.zip https://files.cnblogs.com/files/chenghu/git-gui-zh-master.zip 2.找到git安装路径 C:\Program Files\Git\mingw64\share\git-gui\lib 3.解压出1下载的文件 复制粘…

VM(CentOS7安装和Linux连接工具以及换源)

目录 一、Linux意义 二、安装VMWare 三、centos7安装 1、正式安装CentOS7&#xff1a; 2、安装不了的解决方案 2.1常见问题——虚拟机开机就黑屏的完美解决办法 3、查看、设置IP地址 ① 查看ip地址&#xff1a;ip addr 或者 ifconfig&#xff0c; 注意与windows环境的区别…

了解区块链---一个去中心化技术

1.假如你是从事区块链的高端技术人员&#xff0c;我从来没有接触过区块链&#xff0c;请你为我讲解下他的概率、原理、应用&#xff1f; 概念&#xff1a; 区块链是一种去中心化的分布式账本技术&#xff0c;它是由一系列区块组成的链式结构&#xff0c;每个区块包含一些交易数…

宋浩线性代数笔记(一)行列式的计算

本帖更新b站宋浩老师的线代网课笔记&#xff0c;内容较为细致详细&#xff0c;参考书用的是科学出版社的第三版&#xff0c;之后会附加同济出版社第六版的教材内容。 &#xff08;字不好看大家将就看吧QAQ&#xff09;

当DevOps遇到AI,黑马迎来3.0时代丨IDCF

随着GhatGPT的爆火&#xff0c;人工智能和研发效能&#xff0c;无疑成为了2023的两个最重要的关键词。大规模语言模型LLM和相关应用的快速发展正在对研发团队的工作方式产生深远影响&#xff0c;这几乎象征着新的生产力革命的到来。 那么&#xff0c;作为一名工程师&#xff0…

java密码强度校验

一、代码 Testpublic void test(){//包含数字、大小写字母&#xff0c;长度10-20位 String regular "^(?.*\\d)(?.*[a-z])(?.*[A-Z]).{10,20}$";String example1 "1234567891";System.out.println(example1.matches(regular)); //falseString exa…

React(2)

题外话&#xff1a;vscode有个插件可以很方便的快速写代码 输入rcc回车 1.组件嵌套 import React, { Component } from reactclass Navbar extends Component{render(){return <div>Navbar</div>} }const Swiper()>{return <div>Swiper</div> }cons…

数据库信息速递 MONGODB 6.0 的新特性,更多的查询函数,加密查询,与时序数据集合 (译)...

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到3群&#xff08;共…

linux安装redis

背景 项目需要 安装redis&#xff0c;不使用root用户,假设使用redis用户。 root准备 安装依赖 yum install gcc安装目录 mkdir /usr/local/redis授权安装目录 注意&#xff0c;先要新建用户 chown -R redis:redis /usr/local/redis 安装 切换用户 下载 下载包地址 h…

Spring实现文件上传,文件上传

第一步&#xff1a;创建jsp文件 创建form表单 提交文件是post 文件上传的表单 服务端能不能获得数据&#xff0c;能 实现单文件上传的步骤&#xff1a; 导入相应的坐标&#xff1a;在pom.xml文件中进行导入 再导入这份&#xff1a; 第二步&#xff0c;在spring-MVC的上传中去配…

中文分词入门:使用IK分词器进行文本分词(附Java代码示例)

1. 介绍 中文分词是将连续的中文文本切分成一个个独立的词语的过程&#xff0c;是中文文本处理的基础。IK分词器是一个高效准确的中文分词工具&#xff0c;采用了"正向最大匹配"算法&#xff0c;并提供了丰富的功能和可定制选项。 2. IK分词器的特点 细粒度和颗粒…

Zookeeper简介及核心概念

一、Zookeeper简介 二、Zookeeper设计目标 三、核心概念 3.1 集群角色 3.2 会话 3.3 数据节点 3.4 节点信息 3.5 Watcher 3.6 ACL 四、ZAB协议 4.1 ZAB协议与数据一致性 4.2 ZAB协议的内容 五、Zookeeper的典型应用场景 5.1数据的发布/订阅 5.2 命名服务 5.3 Master选举 5.4 分…

2023云曦期末复现

目录 WEB sign SSTI serialize WEB sign 有10000个 进行bp爆破 能发现 410 和 414长度 还有 420 410 414存在16进制的字符 拼凑出来为 \x66\x6c\x61\x67\x7b\x61\x63\x63\x39\x39\x66\x39\x30\x34\x66\x30\x65\x61\x66\x61\x34\x31\x63\x30\x36\x34\x33\x36\x38\x31\x3…

一、对象的概念(3)

本章概要 单继承结构集合对象创建与生命周期异常处理其它 单继承结构 自从 C 引入以来&#xff0c;一个 OOP 问题变得尤为突出&#xff1a;是否所有的类都应该默认从一个基类继承呢&#xff1f;这个答案在 Java 中是肯定的&#xff08;实际上&#xff0c;除 C 以外的几乎所有…