转自: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方法

上图中看到可以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、LifecycleOwner、LifecycleObserver 三者关系

到此Lifecycle相关部分介绍的差不多了,但是还不够,官方还提供了其他已经封装好的能感知Lifecycle组件生命周期的配套组件LiveData和ViewModels。

3 LiveData

LiveData的作用是持有一份给定的数据,并且能够在生命周期变化中观察它。该类为开发者提供了一系列方法,方便对这个类持有数据的观察者的管理。LiveData会根据观察者绑定的LifecycleOwner的生命周期情况,来决定是否将数据改变的情况通知给观察者。这么做的好处就是,比如在一个Activity里面请求了网络更新这个Activity A界面下的数据,但是如果数据还没有请求回来这时候用户跳转到了另一个Activity B,这时候如果这个数据是被LiveData所持有的,那么这个被网络请求更新的数据就不会通知给Activity A。

LiveData的处理逻辑如下图所示:

 
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 更改时自动保留数据。

 
ViewModel生命周期

官方给的建议是将LiveData和ViewModel配合来使用。当不需要ViewModel时(比如Activity调用finish()方法),ViewModel会回调onCleared()方法,之后会销毁自己。这一好处也是避免了内存泄漏的情况发生。

 
Activity正常销毁时的ViewModel

例子如下:


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的更多相关文章

  1. 【Android】ViewModel+LiveData:更加直接地控制视图的方式

    目录 LiveData 前言 使用ViewModel+LiveData LiveData 前言   ViewModel通过将UI data保存在ViewModel类实例的内部,从而大大地将MVC中的 ...

  2. Android lifecycle 使用详解

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/gdutxiaoxu/article/det ...

  3. 【Medium 万赞好文】ViewModel 和 LIveData:模式 + 反模式

    原文作者: Jose Alcérreca 原文地址: ViewModels and LiveData: Patterns + AntiPatterns 译者:秉心说 View 和 ViewModel ...

  4. ViewModel、LiveData、DataBinding

    ViewModel ViewModel的引入 如果系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失.例如,应用的某个 Activity 中可能包含用户列表.因配置更改而重新创 ...

  5. android MVVM(1)用LiveData关联VM 与 V

    1.官方文档 MVVM 官方文档: https://developer.android.com/jetpack/docs/guide ViewModel 文档: https://developer.a ...

  6. Jetpack架构组件学习(2)——ViewModel和Livedata使用

    要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝 原文地址:Jetpack架构组件学习(2)--ViewModel和Livedata使用 | Stars-One ...

  7. Android lifecycle 实战及使用进阶

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/gdutxiaoxu/article/det ...

  8. ViewModel和LiveData问题思考与解答

    嗨,大家好,面试真题系列又来了,今天我们说说MVVM架构里的两大组件:ViewModel和LiveData. 还是老样子,提出问题,做出解答. ViewModel 是什么? ViewModel 为什么 ...

  9. Jetpack的ViewModel与LiveData

    本文基于SDK 29 一.ViewModel与LiveData的作用: 1.viewModel: 数据共享,屏幕旋转不丢失数据,并且在Activity与Fragment之间共享数据. 2.LiveDa ...

随机推荐

  1. Docker的centos镜像内无法使用systemctl命令的解决办法

    在Docker官方的centos镜像内无法使用systemctl命令的解决办法, 使用该命令docker报错 Failed to get D-Bus connection: Operation not ...

  2. Linux下的 sniff-andthen-spoof程序编写

    Linux下的 sniff-andthen-spoof程序编写 一.任务描述 在本任务中,您将结合嗅探和欺骗技术来实现以下嗅探然后欺骗程序.你需要两台机器在同一个局域网.从机器A ping IP_X, ...

  3. 『动善时』JMeter基础 — 57、Linux系统中运行JMeter脚本

    目录 1.Linux系统中安装Java环境 (1)解压Java安装包 (2)配置Java环境变量 (3)验证Java环境是否配置成功 2.Linux系统中安装JMeter (1)下载JMeter (2 ...

  4. Python Nose 自动化测试框架介绍

    文章目录 1. unittest 简介 1.1 python 单元测试 1.2 unittest 测试框架 1.3 默认模式 1.4 手工模式 2. nose 扩展框架 2.1 `nose` 的安装和 ...

  5. vue项目部署到docker中

    通过nginx镜像部署 vue项目npm run build打包成dist目录,有的打包会加上版本号 启动 docker 将dist目录通过xftp拷贝到linux服务器上,同目录下新建Dockerf ...

  6. python一对一教程:Computational Problems for Physics chapter 1-B Code Listings 1.7 - 1.12

    作者自我介绍:大爽歌, b站小UP主 ,直播编程+红警三 ,python1对1辅导老师 . 本博客为一对一辅导学生python代码的教案, 获得学生允许公开. 具体辅导内容为<Computati ...

  7. 容器安全产品Aqua调研

    前言 近年来,随着云计算的发展,企业数字化的进程不断加快,业务纷纷开始上云,云原生的概念最近两年也是十分火热,在新业务场景下也随之产生了新的安全问题,如k8s安全.devsecops.微服务安全.Se ...

  8. 一个初步的lilypond模板

    代码文档在下方,涉及了许多基本的文档操作,包括: 1)页面设置,包括纸张大小.页边距 2)段落设置,包括不同内容之间的行距 3)乐谱设置,包括设置谱子大小.谱号.调号.拍号,甚至还有拍号/小节线不可见 ...

  9. 微服务改造之Openfeign的强化插件

    在接触 Spring Cloud 这套框架之前,笔者使用的一直是Dubbo.在转型到Spring Cloud 后,发现了一个很郁闷的问题.Spring Cloud 中的 Openfeign,相比于 D ...

  10. 链式调用Builder

    使用Lombok实现链式调用 1.静态调用 User对象: 对象中必须有一个值不为空staticname作为指定的参数并调用对象 @Accessors(chain = true) @Getter @S ...