转自: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. 禁用root直接远程登录,使用普通账号登录后再切换root

    1.创建一个普通用户 #useradd test 2.给test设置密码 #passwd test 3.禁用root远程登录 #vim /etc/ssh/sshd_config #PermitRoot ...

  2. Iceberg概述

    背景 随着大数据领域的不断发展, 越来越多的概念被提出并应用到生产中而数据湖概念就是其中之一, 其概念参照阿里云的简介: 数据湖是一个集中式存储库, 可存储任意规模结构化和非结构化数据, 支持大数据和 ...

  3. Java测试开发--sts安装Lombok(七)

    1.sts安装Lombok的步骤: 下载最新的lombok.jar包,进入cmd窗口,切到Lombok下载的目录,运行命令: java -jar lombok.jar,会出现如下界面: 已经默认选好了 ...

  4. Java多线程 | 02 | 线程同步机制

    同步机制简介 ​ 线程同步机制是一套用于协调线程之间的数据访问的机制.该机制可以保障线程安全.Java平台提供的线程同步机制包括: 锁,volatile关键字,final关键字,static关键字,以 ...

  5. PTA 7-2 邻接表创建无向图 (20分)

    PTA 7-2 邻接表创建无向图 (20分) 采用邻接表创建无向图G ,依次输出各顶点的度. 输入格式: 输入第一行中给出2个整数i(0<i≤10),j(j≥0),分别为图G的顶点数和边数. 输 ...

  6. 『学了就忘』Linux基础命令 — 38、Linux中光盘的挂载

    目录 步骤一:创建一个空目录 步骤二:找到光盘的设备文件名称 步骤三:挂载光盘 步骤四:访问关盘中的数据 步骤五:卸载挂载点 问题:挂载点为什么要使用空目录 提示:关于Linux系统中光盘的挂载,我们 ...

  7. 问题 K: 找点

    题目描述 上数学课时,老师给了LYH一些闭区间,让他取尽量少的点,使得每个闭区间内至少有一个点.但是这几天LYH太忙了,你们帮帮他吗? 输入 多组测试数据. 每组数据先输入一个N,表示有N个闭区间(N ...

  8. MySQL基础语句(MySQL内置函数 )

    MySQL 字符串函数 函数 描述 实例 ASCII(s) 返回字符串 s 的第一个字符的 ASCII 码. 返回 CustomerName 字段第一个字母的 ASCII 码: SELECT ASCI ...

  9. jpg与jpeg的区别在哪

    JPG文件的优点是体积小巧,并且兼容性好,因为大部分的程序都能读取这种文件,这是因为JPG格式不仅是一个工业标准格式,而且更是web的标准文件格式.JPG文件如此拥有如此便利的条件,难怪得到了业余玩家 ...

  10. [tc13008]Egalitarianism2

    考虑对于$n-1$个数$a_{i}$,函数$f(x)=\frac{\sum_{i=1}^{n-1}(x-a_{i})^{2}}{n-1}$的最小值恰在$x=\frac{\sum_{i=1}^{n-1} ...