转 Android Lifecycle、ViewModel和LiveData
转自:https://www.jianshu.com/p/982545e01d0a
1、概述
在I / O '17的时候,其中一个重要的主题是Architecture Components。这是一个官方的新库。旨在帮助开发者设计“健壮,可测试和可维护”的应用程序。简而言之,这个库可以帮助开发者更好地处理生命周期事件和配置更改时的数据持久性,同时还能帮助开发者创建更好的体系结构应用程序,并避免难以维护和测试的膨胀类。
其官方文档在这里:Android Architecture Components
这里我打算详细讨论下Architecture Components里面的Lifecycle、ViewModel和LiveData这3个部分。先看一下这三者的类和相关类的关系图:
粗一看有些复杂,接下来会详细分析下各个部分负责的内容。
2、Lifecycle
根据官方文档,Lifecycle是一个抽象类,一个有Android 生命周期的对象附在它上面, 并且它持该对象的当前生命周期所处状态,所以其他对象可以观察到这种状态并做出相应的反应。为了跟踪这种状态,Lifecycle类包含两个枚举类Event和State。
2.1 Event
一个Event代表当Android 生命周期的对象的生命周期发生改变时候,会触发的一个生命周期事件(例如一个activity正在被恢复)。在LifecycleObserver类中,可以为每个事件实现回调,这样在生命周期的对象的生命周期改变的时候我们能进行相关的处理。arch.lifecycle包提供了Annotation,这意味着可以在类中注释应该在某些生命周期事件中触发的方法。比如像下面这样:
@OnLifecycleEvent(ON_STOP)
void doSometing(){
}
还可以在同一个带注释的方法中处理多个生命周期事件:
@OnLifecycleEvent({ON_STOP,ON_START})
void doSometing(){
}
下面是各种事件的情况:
① ON_ANY:在任何生命周期事件时触发。
② ON_CREATE:创建LifecycleOwner(下面会讲这个类)时将触发此事件。
③ ON_DESTROY:LifecycleOwner被销毁时将触发此事件。
④ ON_PAUSE:LifecycleOwner暂停时将触发此事件。
⑤ ON_RESUME:在LifecycleOwner恢复时触发此事件。
⑥ ON_START:启动LifecycleOwner时触发此事件。
⑦ ON_STOP:LifecycleOwner停止时触发此事件。
ON_CREATE,ON_START,ON_RESUME的方法会在LifeCycleOwner对应方法(onCreate()、onStart()、onResume())返回后被调用。生命周期事件ON_DESTROY, ON_STOP, ON_PAUSE的方法会在LifeCycleOwner对应方法(onDestory()、onStop()、onPause()被调用之前调用。
2.2 State
生命周期的State本质上是介于两个生命周期事件之间的一种情况。触发事件后,生命周期将进入一个状态,然后在触发另一个事件时离开该状态并进入另一个状态。如下图所示:
从上图可以看到,Lifecycle实例在任意时间段里肯定是下面五个状态的其中一种:
① INITIALISED:初始起点的生命周期状态。
② CREATED:ON_CREATE事件之后,ON_START事件之前的状态。或者是ON_STOP事件之后,ON_DESTROY事件之前的状态。
③ STARTED:ON_START事件之后,ON_RESUME事件之前的状态。或者是事件之ON_PAUSE后,ON_STOP事件之前的状态。
④ RESUMED:ON_RESUME事件之后的状态。
⑤ DESTROYED:ON_DESTROY事件之后的状态。
如果想获取Lifecycle实例的当前状态,那么可以调用getCurrentState()方法,该方法允许开发者在任何时间检索其当前状态。这有助于在执行某种形式的操作之前检查Lifecycle组件的状态。State对象还可以调用isAtLeast()方法来判断当前状态是否大于等于给定状态。
2.3 Lifecycle相关方法
了解了Lifecycle所包含的State和Event枚举类,现在看看Lifecycle和其它类进行交互的一些方法。
上图中看到可以Lifecycle的核心方法主要用来管理观察者:
① addObserver():该方法用来添加一个Observer实例,只要LifecycleOwner改变状态就会通知它。当添加一个Observer时,它将接收导致当前状态的所有事件。举例来说,如果Lifecycle目前在RESUMED状态,则观察员将收到ON_CREATE,ON_START和ON_RESUME事件。
② removeObserver():可以调用此方法从Lifecycle的观察者列表中删除给定的观察者。从生命周期中删除观察者将不再接收任何触发事件。
③ getCurrentState():返回生命周期所在的当前状态。
前面提到了一个和Lifecycle息息相关的类LifecycleOwner,接下来看一下这个类是干什么的。
2.4 LifecycleOwner
这个其实是一个接口类,里面只有一个方法getLifecycle()
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
里面的唯一方法getLifecycle()就是用来返回Lifecycle的。而这个方法的所代表的意思很简单,告诉要使用Lifecycle的组件,我是一个生命周期感知组件,我存在生命周期的概念。我们现在看v4组件下的Activity,会继承自SupportActivity,和Fragment,这两个类都实现了LifecycleOwner这个接口。同时这两个类有一个LifecycleRegistry属性,这个属性就是继承自Lifecycle而LifecycleOwner的getLifecycle()返回的就是这个LifecycleRegistry。这样就可以通过这个方法获取该Activity的Lifecycle,再通过对Lifecycle的观察对Activity的生命周期进行观察,如下:
class MainActivity extends AppCompatActivity() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
getLifecycle().addObserver(new SomeObserver())
}
}
SomeObserver类继承自LifecycleObserver,如下所示
class SomeObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void MyResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void MyPause() {
}
}
这样的话,当MainActivity 触发相应的事件,SomeObserver 就会回调相应的方法。
到此Lifecycle相关部分介绍的差不多了,但是还不够,官方还提供了其他已经封装好的能感知Lifecycle组件生命周期的配套组件LiveData和ViewModels。
3 LiveData
LiveData的作用是持有一份给定的数据,并且能够在生命周期变化中观察它。该类为开发者提供了一系列方法,方便对这个类持有数据的观察者的管理。LiveData会根据观察者绑定的LifecycleOwner的生命周期情况,来决定是否将数据改变的情况通知给观察者。这么做的好处就是,比如在一个Activity里面请求了网络更新这个Activity A界面下的数据,但是如果数据还没有请求回来这时候用户跳转到了另一个Activity B,这时候如果这个数据是被LiveData所持有的,那么这个被网络请求更新的数据就不会通知给Activity A。
LiveData的处理逻辑如下图所示:
3.1 setValue()
当调用LiveData的setValue(T value)方法时,将设置LiveData持有的数据。判断是否有活跃的观察者,这里的活跃观察者指观察者绑定的LifecycleOwner中的Lifecycle处于STARTED和RESUMED状态的观察者,如果有的话,将更新的数据发送给这些处于活跃状态的观察者。
3.2 observe()
当调用的LiveData的observe(LifecycleOwner owner, Observer observer)方法时,根据情况会有不同的处理。如果LifecycleOwner处于DESTROYED状态,那么这个调用将被完全忽略。如果它不是DESTROYED,那么此时观察者Observer将被添加到LiveData的观察者列表中,同时该观察者会LifecycleOwner绑定,如果LifecycleOwner的生命周期状态变成DESTROYED,那么和这个LifecycleOwner绑定的观察者会自动被移除,这么做的好处就是可以避免很多可能会出现的内存泄漏。同时如果之前LiveData已经被设置过数据了,那么观察者会立刻接收到最新的数据。
如果之前LiveData没有观察者观察它,那第一次接受观察者会回调LiveData的onActive()方法。这个方法里面可以执行一些数据拉取操作,使数据处于处于最新状态,回调这个方法意味着该LiveData正在被使用中。
3.3 removeObserver()
这个方法有两个重载方法 removeObserver(Observer observer)和 removeObservers(LifecycleOwner owner) 一个是移除观察者,一个是移除和该LifecycleOwner所绑定的所有观察者。
如果LiveData的观察者列表中不存在活跃观察者了,也就是说没有一个观察者绑定的LifecycleOwner的Lifecycle处于 STARTED 或者RESUMED状态。这时候LiveData会回调onInactive()。这时候就算其持有的数据更新了,也不会发起通知。
3.4 其他方法
① hasActiveObservers():检查LiveData中是否有活跃的观察者。
② hasObservers():检查LiveData中是否有观察者。
③ observeForever(Observer observer):用于将一个Observer添加到一个活跃列表中,该列表将始终保持ACTIVE状态,因此永远不会自动从Observer实例列表中移除它。要移除此Observer时必须手动调用removeObserver()。
④ postValue(T value):在主线程中给LiveData设置值。
Tips:LiveData中的setValue(T value)、postValue(T value)都是protected,也就是说只能自己或者它的继承类进行调用。如果想在外面调用这些方法可以使用它的继承类MutableLiveData。
4、ViewModel
4.1 ViewModel实现
ViewModel这个类设计出来的目的是为了解决configuration 改变时候,Activity会重建,这时候里面的数据不易保存的问题。有了它Activity或者Fragment就可以不需要承担保留数据的责任了,可以把这些事情交给ViewModel,做到很好的数据和视图的解耦。同时ViewModel会在configuration 更改时自动保留数据。
官方给的建议是将LiveData和ViewModel配合来使用。当不需要ViewModel时(比如Activity调用finish()方法),ViewModel会回调onCleared()方法,之后会销毁自己。这一好处也是避免了内存泄漏的情况发生。
例子如下:
public class MyViewModel extends ViewModel {
private MutableLiveDatam<Integer> mValue= new MutableLiveData<>();
public LiveData getValue(){
return mValue;
}
public void setValue(Integer value ){
mValue.setValue(value);
}
}
Tips: ViewModel可能比它所涉及的一些Activity/Fragment实例存活时间更长。因此不要保留 Activity的Context和View相关的任何引用,不然可能引起内存泄漏。如果想引用Application的Context,可以使用AndroidViewModel,可以通过其getApplication()来获取。
4.2 ViewModel使用
ViewModel的创建不能通过简单的new对象来进行。需要通过activity / fragment 获取ViewModel实例。为此,需要访问一个名为ViewModelProviders的辅助类 ,通过这样获取的ViewModel对于一个activity 只有一份:
MyViewModel mMyViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel .class);
ViewModelProviders这个类,本质上其实是一个工厂类。这个类内部包含了一个ViewModelStore实例,它负责存储创建的ViewModels。同时可以使用ViewModelProvider的get()方法来获取作为参数传入的ViewModel类型的实例。该方法源码如下:
@NonNull@MainThreadpublicT get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
// 无需检查之间返回
return (T) viewModel;
} else {
if (viewModel != null) {
// 输出警告日志
}
}
// 创建一个ViewModel 对象并存入ViewModelStore。
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
如源码所示,当调用此get()方法时,ViewModelProvider将检查ViewModelStore是否已具有该类类型的现有ViewModel,如果是,则将返回它。但是,如果不存在,那么将创建一个新的ViewModel并将其添加到ViewModelStore中。
获取到ViewModel 就可以使用里面的属性和方法来进行操作了。下面说明下ViewModel存在的意义。
4.3 ViewModel 意义
ViewModel 被设计出来,不仅为了解决上面所说的configuration改变时候能保留数据。其真正意义在于以下几个方面:
① 职责分离:使Activity/Fragment不用再负责从某些数据源获取数据,只需要负责展示数据就好,同时还消除了在配置更改时保留数据对象实例的引用的责任。这两个职责都转给了ViewModel。
② 简化对没用数据的清理:当Activity/Fragment负责清理数据的操作时,需要使用大量代码来清理这些请求。但是将这些清理操作放到ViewModels onCleared()方法中,这些资源在Activity结束时会自动清除。
③ 减少类的膨胀:由于职责的转移,Activity/Fragment删除了许多用于处理请求,状态持久性和注销数据的代码。这些代码通常会导致Activity/Fragment变得非常臃肿,这样的代码会难以扩展和维护。使用ViewModels可以帮助开发者缓解Activity/Fragment的膨胀,使各个类的职责尽可能单一。
④ 容易测试:职责的分离会使测试这些职责更容易,而且还可以产生更细粒度的测试用例。
作者:高丕基
链接:https://www.jianshu.com/p/982545e01d0a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
转 Android Lifecycle、ViewModel和LiveData的更多相关文章
- 【Android】ViewModel+LiveData:更加直接地控制视图的方式
目录 LiveData 前言 使用ViewModel+LiveData LiveData 前言 ViewModel通过将UI data保存在ViewModel类实例的内部,从而大大地将MVC中的 ...
- Android lifecycle 使用详解
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/gdutxiaoxu/article/det ...
- 【Medium 万赞好文】ViewModel 和 LIveData:模式 + 反模式
原文作者: Jose Alcérreca 原文地址: ViewModels and LiveData: Patterns + AntiPatterns 译者:秉心说 View 和 ViewModel ...
- ViewModel、LiveData、DataBinding
ViewModel ViewModel的引入 如果系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失.例如,应用的某个 Activity 中可能包含用户列表.因配置更改而重新创 ...
- android MVVM(1)用LiveData关联VM 与 V
1.官方文档 MVVM 官方文档: https://developer.android.com/jetpack/docs/guide ViewModel 文档: https://developer.a ...
- Jetpack架构组件学习(2)——ViewModel和Livedata使用
要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝 原文地址:Jetpack架构组件学习(2)--ViewModel和Livedata使用 | Stars-One ...
- Android lifecycle 实战及使用进阶
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/gdutxiaoxu/article/det ...
- ViewModel和LiveData问题思考与解答
嗨,大家好,面试真题系列又来了,今天我们说说MVVM架构里的两大组件:ViewModel和LiveData. 还是老样子,提出问题,做出解答. ViewModel 是什么? ViewModel 为什么 ...
- Jetpack的ViewModel与LiveData
本文基于SDK 29 一.ViewModel与LiveData的作用: 1.viewModel: 数据共享,屏幕旋转不丢失数据,并且在Activity与Fragment之间共享数据. 2.LiveDa ...
随机推荐
- Language Server for Java™ 1.0 在VS Code上正式发布!
Nick Zhu form Senior Program Manager, Developer Division at Microsoft 今天,我们很高兴与大家宣布:Language Server ...
- 有关于ONVIF
1.什么是ONVIF2008年5月,由安讯士(AXIS)联合博世(BOSCH)及索尼(SONY)公司三方宣布携手共同成立一个国际开放型网络视频产品标准网络接口开发论坛,取名为ONVIF(Open Ne ...
- Jmeter分布式 (三)
一.什么是分布式测试 分布式测试是指通过局域网和Internet,把分布于不同地点.独立完成特定功能的测试计算机连接起来,以达到测试资源共享.分散操作.集中管理.协同工作.负载均衡.测试过程监控等目的 ...
- xmind 文件 打开后会在当前目录生成 configuration,p2和workspace目录,artifacts.xml文件 解决
在xmind安装目录下的xmind.ini修改如下配置,为绝对路径
- vue强制组件重新渲染
有时候,依赖 Vue 响应方式来更新数据是不够的,相反,我们需要手动重新渲染组件来更新数据.或者,我们可能只想抛开当前的DOM,重新开始.那么,如何让Vue以正确的方式重新呈现组件呢? 强制 Vue ...
- mysql查询报错this is incompatible with sql_mode=only_full_group_by
临时改法:select @@GLOBAL.sql_mode;查询当前mysql的模式去掉ONLY_FULL_GROUP_BY重新设置:set @@GLOBAL.sql_mode='STRICT_TRA ...
- [spojRNG]Random Number Generator
先将所有数加上Ri,即变为区间[0,2Ri],考虑容斥,将区间容斥为[0,+oo)-[2Ri,+oo),然后对[2Ri,+oo)令$bi=ai-2Ri$,相当于范围都是[0,+oo)问题转化为求n个正 ...
- [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化
[源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化 目录 [源码解析] PyTorch 分布式(9) ----- DistributedD ...
- 收集的常用的CTF学习资源网站
http://www.sec-wiki.com/skill/ 安全技能学习路线(迷茫就看它) https://wiki.x10sec.org/ 介绍了CTF各个方向的基础知识 ...
- Flink 实践教程-入门(8): 简单 ETL 作业
作者:腾讯云流计算 Oceanus 团队 流计算 Oceanus 简介 流计算 Oceanus 是大数据产品生态体系的实时化分析利器,是基于 Apache Flink 构建的具备一站开发.无缝连接.亚 ...