LiveData的用法
一.实时数据LiveData
在上一节中,我们学习了ViewModel,了解到ViewModel的主要作用是存放页面所需要的各种数据。我们在示例代码中定义了接口,当数据发生变化的时候,采用接口的方式实现对页面的通知。但是这种方式是有缺陷的,当要存储的数据非常多的时候,就要定义大量的接口,代码会显得十分冗余,为此JetPack提供了LiveData组件。LiveData是一个可被观察的数据容器类,具体来说,可以将LiveData理解为一个数据的容器,它将数据包装起来,使数据成为被观察者,当数据发生变化的时候,观察者能够获得通知。我们不需要自己去实现观察者模式,LiveData内部已经默认实现好了。
下面我们用LiveData替代上一节定义的接口,完成ViewModel和页面之间的通信。
二.LiveData和ViewModel的关系
ViewModel用于存储页面所需要的数据,不仅如此,我们还可以在其中放一些与数据相关的业务逻辑。例如,可以在ViewModel中进行数据的获取和加工等操作。因此,ViewModel中的数据可能随着业务的变化而发生变化。对页面来说,它并不关心ViewModel的业务逻辑,它只关心需要展示的数据是什么,并且希望在数据发生变化的时候,能及时得到通知并做出更新。LiveData的作用就是,在ViewModel中的数据发生变化的时候通知页面更新。因此,LiveData通常被放在ViewModel中使用,用于包装ViewModel中那些需要被外界观察的数据。
三.LiveData的基本使用方法
LiveData是一个抽象类,不能直接使用,通常使用的是他的直接子类MutableLiveData。下面我们改造上一节的代码,如下所示:
public class TimerViewModel extends ViewModel {
private MutableLiveData<Integer> currentSecond;
private Timer timer;
private Integer second=0;
@Override
protected void onCleared() {
super.onCleared();
timer.cancel();
}
public void startTiming(){
if(timer==null){
timer=new Timer();
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
second++;
currentSecond.postValue(second);
}
};
timer.schedule(timerTask,1000,1000);
}
}
public LiveData<Integer> getCurrentSecond(){
if(currentSecond==null){
currentSecond=new MutableLiveData<>();
}
return currentSecond;
}
}
public class MainActivity extends AppCompatActivity {
private TextView tv_display;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iniComponent();
}
private void iniComponent() {
tv_display=findViewById(R.id.tv_display);
TimerViewModel timerViewModel=new ViewModelProvider(this).get(TimerViewModel.class);
MutableLiveData<Integer> liveData= (MutableLiveData<Integer>) timerViewModel.getCurrentSecond();
liveData.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer second) {
tv_display.setText(second+"");
}
});
timerViewModel.startTiming();
}
}
在页面中,通过LiveData.observe()方法对LiveData所包装的数据进行观察,当该数据发生变化的时候,就可以得到更新后的数据,并在onChanged()方法中做出处理。当我们需要修改LiveData中的数据时,可以通过LiveData.postValue()和LiveData.setValue()方法来完成。postValue()方法用在非UI线程,setValue()方法用在UI线程中。
四.LiveData的原理
为了更好地理解LiveData,我们可以深入LiveData.observe()方法的源码一探究竟。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
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);
}
从源码可以看到,observe方法接收的第一个参数是LifecycleOwner对象,在本例中是Activity,第二个参数是一个Observer对象。从源码中可以发现,当页面的状态为Destroy时,直接return了,否则将observer添加为页面的观察者。也就是说,只有页面处于激活状态时,页面才可以收到来自LiveData的通知,若页面处于destroy状态,那么LiveData会自动清除与页面的关联,从而避免可能引起的内存泄漏问题。
五.LiveData.observeForever()方法
LiveData还提供了一个名为observeForever()的方法,它的用法和observe方法相似,主要的区别在于,当LiveData中的数据发生变化时,无论页面处于什么状态,observeForever()方法都可以收到通知。因此,在用完之后,一定要记得调用removeObserver()方法来停止对LiveData的观察,否则LiveData会一直处于激活状态,Activity则永远不会被系统自动回收,这就造成了内存泄漏。
LiveData的用法的更多相关文章
- Android Weekly Notes Issue #258
Android Weekly Issue #258 May 21st, 2017 Android Weekly Issue #258 本期内容: 围绕着Google I/O的热潮, 本周的posts除 ...
- Jetpack 架构组件 LiveData ViewModel MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Jetpack架构组件学习(2)——ViewModel和Livedata使用
要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝 原文地址:Jetpack架构组件学习(2)--ViewModel和Livedata使用 | Stars-One ...
- Jetpack的ViewModel与LiveData
本文基于SDK 29 一.ViewModel与LiveData的作用: 1.viewModel: 数据共享,屏幕旋转不丢失数据,并且在Activity与Fragment之间共享数据. 2.LiveDa ...
- EditText 基本用法
title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...
- jquery插件的用法之cookie 插件
一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法
一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...
- python enumerate 用法
A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...
- [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...
随机推荐
- 从零开始使用 ROS CDK 搭建云上解决方案
作者: 金湛 前言 资源编排服务ROS(Resource Orchestration Service)是阿里云提供的一项简化云计算资源管理的服务.开发者和管理员可以编写模板,在模板中定义所需的阿里云资 ...
- 【GIT】学习day04 | 将本地代码推送到码云仓库中进行管理【外包杯】
仓库代码页 将本能仓库和码云仓库进行关联 代码组成 git remote add origin 加上下面的地址 将本地仓库的代码推送到码云仓库上 git push -u origin master 之 ...
- STM32外设:通用输入输出 GPIO、EXIT
主要外设: GPIO:General Purpose I/O 一般用途IO EXIT:External Interrupt/Event Controller 外部中断/事件控制器(STM32) 辅助外 ...
- 用pycharm创建一个django框架
用pycharm创建一个django框架 注意解释器的选择和文件路径 创建完django项目 1.自动创建了一个templates目录(先删除) 2.把settings里的 TEMPLATES = [ ...
- Mock框架moco学习笔记
目录 一.Moco框架基本介绍 1. 什么是Moco 2. Moco原理简介 3. Moco的配置和运行 4. Moco启动以及第一个demo 二.mock 的启动及第一个demo 1. 创建star ...
- 【UniApp】-uni-app-CompositionAPI传递数据
前言 好,经过上个章节的介绍完毕之后,了解了一下 uni-app-传递数据 那么了解完了uni-app-传递数据之后,这篇文章来给大家介绍一下 uni-app-CompositionAPI传递数据 首 ...
- 江西财经大学第一届程序设计竞赛 H题- 小P的数学问题
题目链接:https://www.nowcoder.com/acm/contest/115/H 解题思路:分块打表!!! 什么是分块打表呢??? 从这道题我们知道我们要找到最多1*e9的阶乘 那循环暴 ...
- Java中“100==100”为true,而"1000==1000"为false?
前言 今天跟大家聊一个有趣的话题,在Java中两个Integer对象做比较时,会产生意想不到的结果. 例如: Integer a = 100; Integer b = 100; System.out. ...
- Java 并发编程(二 )Thread
线程状态 线程一般的状态转换图如下: 在线程生命周期中存在的状态解释如下: New(初始化)状态 此时线程刚刚被实例化,可以通过调用 start() 方法来启动这个实例化的的线程,使其状态转变成为 R ...
- 实战案例丨代码优化:如何去除context中的warning?
在一个java语言群里面,有人抛了这么一段代码出来,问题是出现了下下图中的warning,问有什么好的方法消除 这种强转都是因为类型链条断掉了,写入的时候擦除了类型,读出来的时候也就只能强转了,那个i ...