Android的LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者

若观察者(Observer)的生命周期处于STARTEDRESUMED状态,则LiveData会认为该Observer处于活跃状态。LiveData只会将更新通知给活跃的Observer。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 activity 和 fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。

使用LiveData的优势

确保界面符合数据状态:LiveData遵循观察者模式。当底层数据发生变化,LiveData会通知Observer对象,此时我们可以写入逻辑,以在Observer中更新界面。这样一来,我们就不用每次在数据发生变化时更新界面,因为Observer会完成这一内容;

不会发生内存泄漏:Observer绑定到LifeCycle对象,并在其关联的生命周期结束后自动清理,这一点与ViewModel类似;

不会因为Activity停止而导致崩溃:若Observer的生命周期处于非活跃状态(如返回对战的activity),它就不会接受LiveData事件;

不需要手动处理生命周期:界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化;

使用LiveData对象

当更新存储在LiveData对象中的值时,它会触发所有已注册的Observer(只要它所附加的Life cycleOwner处于活跃状态)。

创建

LiveData对象通常存储在ViewModel对象中,并可以使用getter方法访问:

class NameViewModel : ViewModel() {// LiveData可用于任何类型的数据,此处创建一个String类型的LiveData对象val currentName: MutableLiveData<String> by lazy {//使用lazy懒加载,当需要使用再创建MutableLiveData<String>()}// ViewModel的剩余部分...
}

存储在ViewModel中、而不是activity或fragment的原因是:

  • 避免activity和fragment过于庞大。我们使用MVVM架构的原因之一,就是为了使这些界面控制器只负责显示数据,而不存储数据;
  • 将LiveData实例与特定的activity或fragment实例分离开,使得LiveData对象在配置更改后仍然存在。

观察

大多数时候,从组件onCreate方法中开始观察LiveData对象,以确保系统不会从onResume方法中进行冗余调用,并确保activity或fragment变为活跃状态后具有可以立即显示的数据。一旦组件处于STARTED状态,就会从它观察的LiveData接受最新的值。

另外,除了LiveData在发生数据更改时会发送更新,Observer从非活跃状态变为活跃状态时也会收到更新。但是,如果Observer第二次发生这样的状态改变,则只有上次的改变会收到更新。

class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的内容...// 创建观察ui更新的observerval nameObserver = Observer<String> { newName ->// 更新ui,此处是一个TextViewnameTextView.text = newName}// 观察LiveData, 将此activity作为LifecycleOwner和observermodel.currentName.observe(this, nameObserver)}
}

我们也可以简写这一部份:

class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的内容...// 简写nameTextView.text = model.currentName.observeAsState()}
}

在传递nameObserver参数的情况下调用observe方法后,系统会立即调用onChanged方法,从而提供mCurrentName中存储的最新值。若LiveData对象上为在mCurrentName中设置值,系统不会调用onChanged方法。

更新

LiveData没有公开可用的方法来更新存储的数据。如果需要修改存储在LiveData对象中的值,需要重写MutableLiveData中的setValue方法或postValue方法。

通常情况下会在ViewModel中使用MutableLiveData,然后ViewModel只会向观察者公开不可变的LiveData对象。设置观察者关系之后,我们就可以更新LiveData对象的值:

button.setOnClickListener {val anotherName = "John Doe"model.currentName.setValue(anotherName)
}

在主线程中我们使用setValue方法更新数据,而在工作器线程中,我们可以改用postValue方法来更新Livedata对象。

扩展LiveData 

如果观察者的生命周期处于STARTED或RESUMED状态,则LiveData会认为该观察者处于活跃状态,以下是扩展LiveData类的例子:

//价格监听器
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}//当LiveData对象具有活跃观察者时,会调用此方法override fun onActive() {//从此方法开始观察股价更新stockManager.requestPriceUpdates(listener)}//当LiveData对象没有活跃观察者时,会调用此方法override fun onInactive() {//断开StockManager服务stockManager.removeUpdates(listener)}
}

接下来我们使用重写后的StockLiveData类:

public class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)val myPriceListener: LiveData<BigDecimal> = ...myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}
}

组件如activity、fragment在初始化时构建了自己的LifecycleOwener。此处的observe方法将与Fragment视图关联的LifecycleOwner作为第一个参数传递,这样做表示此观察者已绑定到与其所有者关联的Lifecycle对象(即组件,在此处是MyFragment),这意味着;

  • 如果Lifecycle对象未处于活跃状态,即使值发生更改,也不会调用观察者;
  • 销毁Lifecycle对象后,会自动移除观察者。

同时LiveData对象具有生命周期感知能力,意味着我们可以在多个activity、fragment和service之间共享这些对象。

我们也可以将StockLiveData实现为一个单例(companion object):

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager: StockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}override fun onActive() {stockManager.requestPriceUpdates(listener)}override fun onInactive() {stockManager.removeUpdates(listener)}companion object {private lateinit var sInstance: StockLiveData@MainThreadfun get(symbol: String): StockLiveData {sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)return sInstance}}
}

为什么使用了单例?以StockLiveData为例,单例的好处是在使用时不需要再创建一个StockLiveData的实例,而是直接引用它的方法:

class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}

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

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

相关文章

ChatGPT在医学领域的应用与前景

标题&#xff1a; ChatGPT在医学领域的应用与前景 正文&#xff1a; 随着人工智能技术的不断进步&#xff0c;ChatGPT等语言模型在医学领域的应用逐渐深入&#xff0c;展现出其巨大的潜力和广阔的发展前景。作为一个高级的自然语言处理工具&#xff0c;ChatGPT能够理解和生成…

WPF 开发调试比较:Visual Studio 原生和Snoop调试控制台

文章目录 前言运行环境简单的WPF代码实现一个简单的ListBoxVisual Studio自带代码调试热重置功能测试实时可视化树查找窗口元素显示属性 Snoop调试使用Snoop简单使用调试控制台元素追踪结构树Visual/可视化结构树Logical/本地代码可视化树AutoMation/自动识别结构树 WPF元素控制…

基于springboot+vue的房屋租赁管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【OpenAI官方课程】第四课:ChatGPT文本推断Summarizing

欢迎来到ChatGPT 开发人员提示工程课程&#xff08;ChatGPT Prompt Engineering for Developers&#xff09;&#xff01;本课程将教您如何通过OpenAI API有效地利用大型语言模型&#xff08;LLM&#xff09;来创建强大的应用程序。 本课程由OpenAI 的Isa Fulford和 DeepLearn…

手拉手Vite+Vue3+TinyVue+Echarts+TailwindCSS

技术栈springboot3hutool-alloshi-coreVue3viteTinyVueEchartsTailwindCSS软件版本IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1hutool-all5.8.18oshi-core6.4.1Vue35.0.10vite5.0.10axios1.6.7echarts5.4.3 ECharts是一个使用 JavaScript 实现的开源可视化库&#xff0c;可…

快速搭建ARM64实验平台(QEMU虚拟机+Debian)

文章目录 前言一、实验平台介绍二、安装步骤2.1 安装工具2.2 下载仓库2.3 编译内核并制作根文件系统2.4 运行刚才编译好的ARM64版本的Debian系统2.5 在线安装软件包2.6 在QEMU虚拟机和主机之间共享文件 三、单步调试ARM64 Linux内核参考资料 前言 最近翻阅笨叔的《奔跑吧Linux…

go-zero微服务入门教程

go-zero微服务入门教程 本教程主要模拟实现用户注册和用户信息查询两个接口。 准备工作 安装基础环境 安装etcd&#xff0c; mysql&#xff0c;redis&#xff0c;建议采用docker安装。 MySQL安装好之后&#xff0c;新建数据库dsms_admin&#xff0c;并新建表sys_user&#…

【Git】 删除远程分支

Git 删除远程分支有以下几种方法 服务端UI工具 Git 的服务端图形化工具主要是 web 端。常用的有 GitHub、Gitea、Gutlab 等。 这些工具都提供了分支管理&#xff0c;可以直接在各服务端找到相关功能&#xff0c;谨慎删除。 客户端UI工具 Git 拥有诸多客户端 UI 工具&#x…

详细分析Python中的unittest测试框架

目录 1. 基本知识2. API2.1 断言2.2 setUp() 和 tearDown() 3. Demo 1. 基本知识 unittest 是 Python 标准库中的一个单元测试框架&#xff0c;用于编写和执行测试用例以验证代码的正确性 提供了一种结构化的方法来编写测试&#xff0c;使得测试代码更加模块化和易于维护 以…

【ACW 服务端】页面操作Java增删改查代码生成

版本: 1.2.2-JDK17-SNAPSHOT 项目地址&#xff1a;wu-smart-acw 演示地址&#xff1a;演示地址 admin/admin Java增删改查代码生成 找到对应菜单 选择你需要的数据实例 选择数据库 选择数据库表 选择客户端&#xff08;如果是本地ACW服务代码启动默认注册上的客户端ID是…

腾讯云主机Ubuntu22.04安装Odoo17

一、安装PostgreSQL16 参见之前的文章 Ubuntu22.04安装PostgreSQL-CSDN博客 二、安装Odoo17 本方案使用的nightly版的odoo&#xff0c;安装的都是最新版odoo wget -O - https://nightly.odoo.com/odoo.key | apt-key add - echo "deb http://nightly.odoo.com/17.0/n…

Maven【1】(命令行操作)

文章目录 一丶创建maven工程二、理解pom.xml三、maven的构建命令1.编译操作2.清理操作3.测试操作4.打包操作5.安装操作 一丶创建maven工程 首先创建这样一个目录&#xff0c;然后从命令行里进入这个目录&#xff1a; 然后接下来就在这个命令行里进行操作了。 这个命令是&…

Python学习笔记——PySide6设计GUI应用之UI与逻辑分离

1、打开PySide6的UI设计工具pyside6-designer&#xff0c;设计一个主窗口&#xff0c;保存文件名为testwindow.ui 2、使用PySide6的RCC工具把testwindow.ui文件转换为testwindow_rc.py文件&#xff0c;此文件中有一个类Ui_MainWindow&#xff08;包含各种控件对象&#xff09;…

设计模式浅析(八) ·外观模式

设计模式浅析(八) 外观模式 日常叨逼叨 java设计模式浅析&#xff0c;如果觉得对你有帮助&#xff0c;记得一键三连&#xff0c;谢谢各位观众老爷&#x1f601;&#x1f601; 外观模式 概念 外观模式&#xff08;Facade Pattern&#xff09;是一种设计模式&#xff0c;它为…

深度学习发展里程碑事件2006-2024

2006-2024年&#xff0c;深度学习发展经历众多的里程碑事件&#xff0c;一次次地刺激着人们的神经&#xff0c;带来巨大的兴奋。电影还在继续&#xff0c;好戏在后面&#xff0c;期待…… 2006年 深度信念网络&#xff08;DBNs&#xff09;&#xff1a;Geoffrey Hinton与他的学…

备战蓝桥杯 Day10(背包dp)

01背包问题 1267&#xff1a;【例9.11】01背包问题 【题目描述】 一个旅行者有一个最多能装 M&#xfffd; 公斤的背包&#xff0c;现在有 n&#xfffd; 件物品&#xff0c;它们的重量分别是W1&#xff0c;W2&#xff0c;...,Wn&#xfffd;1&#xff0c;&#xfffd;2&#…

蓝桥杯刷题--python-10(2023填空题3)

0工作时长 - 蓝桥云课 (lanqiao.cn) import datetime time_str_list=[] while(True):tmp=input()if not tmp: breaktime_str_list.append(tmp)# time_list=[datetime.datetime.strptime(t,"%Y-%m-%d %H:%M:%S")for t in time_str_list] time_list.sort() sum=0 for i…

【代码随想录算法训练营Day25】● 216.组合总和III ● 17.电话号码的字母组合

文章目录 Day 25 第七章 回溯算法part02216.组合总和III自己的思路&#xff08;✅通过&#xff09; 17.电话号码的字母组合思路代码 Day 25 第七章 回溯算法part02 今日内容&#xff1a; ● 216.组合总和III● 17.电话号码的字母组合 216.组合总和III 如果把 组合问题理解了…

计算机组成原理(9)----硬布线控制器

控制单元CU若想发出对应的控制信号&#xff0c;则需要以下信息&#xff1a;指令操作码&#xff0c;目前的机器周期&#xff0c;节拍信号&#xff0c;机器状态条件&#xff0c;根据这些信息&#xff0c;CU就能确定在这个节拍下应该发出哪些"微命令"&#xff0c;也就是…

SQL注入:使用预编译防御SQL注入时产生的问题

目录 前言 模拟预编译 真正的预编译 预编译中存在的SQL注入 宽字节 没有进行参数绑定 无法预编译的位置 前言 相信学习过SQL注入的小伙伴都知道防御SQL注入最好的方法&#xff0c;就是使用预编译也就是PDO是可以非常好的防御SQL注入的&#xff0c;但是如果错误的设置了…