【用法总结】LiveData组件要点

1、如何实现和生命周期的关联?

调用observe()方法时,第一个参数传入LifecycleOwner对象,而LifecycleOwner能通过getLifecycle()方法获取到lifecycle对象,然后执行lifecycle.addObserver()添加LiveData中数据(mData)变化的观察者对象。

  • observe的实现逻辑:
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        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);
    }

LifecycleOwner-ViewModel-LiveData的层级结构
如上图所示,是使用LiveData组件实现数据更新-订阅的开发模式的层级结构。

  • mData:setValue()之后更新的数据
  • mVersion:在每一次调用setValue()时会进行更新
  • mPending:调用postValue()时先将新的值暂存到该变量中,然后将Runnable任务post()到Handler中后,再将mPendingData
    中的值赋值给mData变量,然后就是走setValue()的流程了。

2、onChange()执行时机

  • (1)onStart()之后调用setValue()立即回调onChanged(newData)

  • (2)调用observe()时,如果Observer是新建的实例,那么其绑定的mLastVersion初始值是-1,当调用lifecycleOwner.addObserver()时会调用activeStateChanged(), 然后触发dispatchingValue(), 因为不满足observe.mLastVersion>=mVersion(默认值是0,每次setValue/postValue加1),然后回调onChanged(newData)
    如果是在onStop()中注册observer,那么会在回到onStart()后会回调一次onChanged()
    ⚠️ LiveData中判断LifecycleOwner是判断生命周期状态是否是isAtLeast(START),所以onPause时调用observe()方法也是会回调onChanged()方法的。

  • (3)LifecycleOwner生命周期变化时,还存在同因生命周期<Lifecycle.State.ON_START并没有回调onChanged(newData),则会回调一次onChanged(),把最新的mData值回调给onChanged()方法

3、说LiveData会数据倒灌是这么回事?

3.1 本质

    LiveData其实本质上实现的是将事件发送时机限定在LifecycleOwner的生命周期内的粘性事件。LiveData在生命周期可见时,将不可见时更新的mData版本回传到onChanged()中。当setValue()是在observe()之前调用的,那调用observe()时会把前面setValue的最新的值传给观察者的onChanged()。
    不使用LiveData进行数据更新时,一般是在UI控件变量准备好了,然后获取数据,再把数据传递给UI控件变量的某个属性,实现UI的更新,这种命令式UI的开发模式本身没有什么问题,符合日常的开发逻辑。
    但是因为Android的UI架构都是基于Activity/Fragment生命周期管理的,就必然存在数据异步获取到时界面已经处于不活跃状态的情况。甚至很可能因为内存不足已经销毁了,然后在用户操作下回到活跃状态了,那么异步拿到的数据可能是没有塞给UI控件的,一般都是在onResume时又异步获取一次数据,然后更新到UI控件上。

3.2 使用LiveData实现事件注册-分发逻辑的问题

    基于3.1对于LiveData数据更新本质的分析,如果我们使用LiveData的setValue/postValue,然后通过observe()分发进行监听,使用String/Int/CustomEvent(自定义的事件类,类似于EventBus)等数据做为事件分发。虽然这种方式能够避免内存泄漏,但是事件是粘性的,先发送事件,然后注册也会接收到该事件,这样的逻辑实际上并不是我们日常业务的事件逻辑。

    google官方sample只处理一次的LiveData事件实现方案:
官方todoapp的Event实现
    ps: 不得不说,老外的文章写得还是蛮清楚的,循序渐进,解释各种方案的问题,层层递进,对读者更好的理解有莫大帮助。

3.3 短时间内连续执行多次postValue,只有最后一次更新的值会收到数据变化的onChanged回调

    这个问题是因为postValue的实现逻辑导致的,如下是postValue的代码:

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

private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

    第一次postValue,postTask是true,mPendingData赋值为value,然后调用mPostValueRunnable.run方法,newValue赋值为mPendingData后,立即又将mPendingData赋值为NOT_SET了。

  • 官方对postValue的备注如下:
    在这里插入图片描述

参考文章

【1】LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1116: 删除元素(数组)

题目描述 输入一个递增有序的整型数组A有n个元素&#xff0c;删除下标为i的元素&#xff0c;使其仍保持连续有序。注意&#xff0c;有效下标从0开始。 定义如下两个函数分别实现删除元素操作和数组输出操作。 void del(int a[], int n, int i); /*删除数组a中下标为i的元素*…

Matlab怎样合并两个矩阵(怎样合并多个矩阵)为一个矩阵

1.合并两个矩阵 a [1 2 3;4 5 6] b [7 8 9;1 2 3] c [a,b] %按行&#xff08;横向&#xff09;合并 c [a;b] %按列&#xff08;纵向&#xff09;合并 2.合并多个矩阵 clc clear temp dir([D:\文件夹\,*.txt]); N length(temp);for i 1:N %先读取文件内所有文件 …

将PDF发票转换为excel、xml结构化数据的完美解决方案

随着电子发票的普及&#xff0c;越来越多的企业和个人开始使用PDF格式的电子发票。然而&#xff0c;有时我们需要将电子发票转换为XML格式以便于处理和分析。本文将介绍如何将收到的PDF发票下载为excel、xml文件。首先&#xff0c;我们需要明确一点&#xff0c;PDF是一种基于图…

(菜鸟自学)搭建虚拟渗透实验室——安装Ubantu 8.10 靶机

安装Ubantu 8.10 靶机 新建虚拟机 选择Ubuntu系统 网络适配器模式选用桥接模式 镜像选用ubuntu8.10版本 点击“开启此虚拟机”以开始安装Ubuntu Linux系统 安装ubuntu 首先需要选择安装时的语言&#xff0c;这里选择“中文&#xff08;简体&#xff09;” 选择“安装…

DAY8--learning english

一、积累 1.haunt Why Ghost dont haunt chinese. 为什么鬼不会出现在中国人旁边? 2.confess i have a confession to make ... I actally a blind. 我要坦白一件事……我其实是个盲人。 3.brake Press S button to brake, or to reverse if the vehicle has stopped, 按住…

QT上位机开发(动画效果)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 不管是仿真&#xff0c;还是对真实环境的一比一模拟&#xff0c;动画都是非常好的一种呈现方式。目前在qt上面&#xff0c;实现动画主要有两种方法…

STM32存储左右互搏 SPI总线FATS读写FRAM MB85RS2M

STM32存储左右互搏 SPI总线FATS读写FRAM MB85RS2M 在中低容量存储领域&#xff0c;除了FLASH的使用&#xff0c;&#xff0c;还有铁电存储器FRAM的使用&#xff0c;相对于FLASH&#xff0c;FRAM写操作时不需要预擦除&#xff0c;所以执行写操作时可以达到更高的速度&#xff0…

Jenkins-自动化

定时构建 使用Cron表达式指定执行时间。 # 格式 # ┌──分&#xff08;0 - 59&#xff09; # │ ┌──时&#xff08;0 - 23&#xff09; # │ │ ┌──日&#xff08;1 - 31&#xff09; # │ │ │ ┌─月&#xff08;1 - 12&#xff09; # │ │ │ │ ┌─星期&#…

构建搜索引擎,而不是向量数据库

英文原文地址&#xff1a;Build a search engine, not a vector DB 构建搜索引擎&#xff0c;而不是矢量数据库 2023 年 12 月 19 日 在过去12个月里&#xff0c;向量数据库初创公司数量激增。我并不是来讨论其中任何一个的具体设计权衡。相反&#xff0c;我想回顾一下向量数…

【Java 设计模式】创建型之单例模式

文章目录 1. 定义2. 应用场景3. 代码实现1&#xff09;懒汉式2&#xff09;饿汉式 4. 应用示例结语 在软件开发中&#xff0c;单例模式是一种常见的设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。单例模式在需要控制某些资源&#xff0c;如数…

正则表达式中的“回引用(回溯)”——别名引用与序号引用的差异及正则表达式中的“P”关键字

读到一段巧妙的正则表达式&#xff0c;勾起我对正则表达式欠缺知识点的探寻&#xff1a; P y t h o n Python Python正则表达式中的“回引用(回溯)”——分组别名引用与序号引用的差异及正则表达式中的“P”关键字详情。 (笔记模板由python脚本于2024年01月14日 07:49:35创建&a…

Makefile编译原理 变量的使用

一.变量和不同的赋值方法 ->makefile中支持程序设计语言中变量的概念 ->makefile中的变量只代表文本数据&#xff08;字符串&#xff09; ->makefile中的变量名规则 - 变量名可以包含字符&#xff0c;数字&#xff0c;下划线。 - 不能包含 ":" "#&…

动态规划篇-04:完全平方数

279、完全平方数 状态转移方程 base case 当n 0 时&#xff0c;和为n的完全平方数的最少数量为0. 明确状态 “原问题或子问题中变化的变量” 在本题中&#xff0c;状态是 “完全平方数的最少数量”。因为当我们选择不同的完全平方数的时候&#xff0c;所需完全平方数的数量…

个人网站制作 Part 5 优化网站性能(图片压缩、代码优化) | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 优化网站性能&#x1f528;图片优化&#x1f527;步骤 1: 使用压缩工具 &#x1f528;代码优化&#x1f527;步骤 2: 压缩CSS和JavaScript&#x1f527;步骤 3: 合并文件…

PCL ISS关键点提取(C++详细过程版)

边界提取 一、概述二、代码实现三、结果展示PCL ISS关键点提取(C++详细过程版)由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 ISS关键点提取在PCL里有现成的调用函数,具体算法原理和实现代码见:PCL ISS关键点提…

性能优化2.0,新增缓存后,程序的秒开率不升反降

目录 一、前情提要经过4次优化&#xff0c;将页面的加载时间控制在了1秒以内&#xff0c;实打实的提升了程序的秒开率。 二、先了解一下&#xff0c;什么是缓存1、缓存有哪些分类2、本地缓存与分布式缓存 三、Guava Cache本地缓存1、Google Guava2、Loadingcache数据结构3、Loa…

上海亚商投顾:创业板指冲高回落 光伏、航运股逆势走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指1月12日冲高回落&#xff0c;创业板指午后跌近1%。北证50指数跌超6%&#xff0c;倍益康、华信永道、众诚科…

SpringBoot 入门教程

1.复习SSM项目中&#xff0c;用spring&#xff0c;mybatis,springmvc这三个框架整合的项目。 SSM项目的所有类&#xff0c;这是用SSM整合一个搜索书籍种类和呈现的前端和后端的ssm的小项目。 2.springboot如何去开发这个页面&#xff1a; 新建springboot项目&#xff0c;勾选对…

【Nuxt3】Nuxt3脚手架nuxi安装项目和项目目录介绍

简言 最近学了Nuxt3,并使用它创建了自己的小网站。记录下学习到的nuxt3内容。 Nuxt3官网 Nuxt 是一个免费的开源框架&#xff0c;可通过直观、可扩展的方式使用 Vue.js 创建类型安全、高性能、生产级的全栈 Web 应用程序和网站。 支持SSR、SPA、建立静态网站&#xff0c;也可以…

分布式限流的主流方案

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 常见的分布式限流方案 前面我们了解了什么是分布式…