LiveData && ViewModel 使用详解

前言在之前的文章中,我们讲了Android Architecture components 中的 Lifecycle 组件的详细使用以及源码解析。本篇将介绍另外AAC中另外两个组件:LiveData 和 ViewModel,它们的实现也都是利用了 Lifecycle。什么是 LiveDataLiveData 是一个可观测的数据持有类,但是不同于通常的被观察者,LiveData 具有生命周期感知能力。通俗点说,LiveData 就是具有 “Live” 能力的 “Data” 持有类。当它所持有的数据发生改变的时候,并且 Lifecycle 对象(比如 Activity 或者 Fragment 等)处于活跃状态(STARTED 或者 RESUMED),LiveData 将立即通知观察者数据发生了变化。也就是说,比普通观察者多了个生命周期感知能力。LiveData 的优势确保UI和数据状态匹配。当数据发生改变的时候,会自动通知UI进行更新。避免内存泄漏Observers 是绑定到 Lifecycle 对象上的,当与其关联的 lifecycle 被销毁的时候,它们会自动被清理。避免了由于 Activity 停止而导致的闪退当 Observer 所绑定的 Lifecycle 处于非活跃状态时,比如处于返回栈中的 Activity,它将不会收到任何 LiveData 事件。不再需要手动处理生命周期UI 组件只需要对相关的数据进行监听,不需要关心是否应该暂停或者恢复监听。LiveData 具有生命周期感知能力,它会自动对这些进行管理。数据总处于最新状态如果一个 Lifecycle 处于非活跃状态,那当它由非活跃状态变为活跃状态的时候,它将收到最新的数据。比如一个 Activity 由后台转为前台,这时候它将立即收到最新的数据系统配置更改时,进行数据的保存和恢复,及 UI 的恢复。当 Activity 或者 Fragment 由于配置更改而重新创建时(比如旋转屏幕等),它将收到最新的可用数据。这里简单提一点,这个有点是需要配合 ViewModel 使用的,严格来说,它主要是 ViewModel 的优点资源共享我们可以使用单例模式来扩展 LiveData,这样就能达到数据变化的时候,通知所有的观察者。为了便于理解,关于 LiveData 和 ViewModel 的关系,我这里先说结论:LiveData 的作用是在使得数据能具有生命周期感知能力,在 Activity 等变为活跃状态的时候,自动回调观察者中的回调方法。也就是说对数据的变化进行实时监听。而 ViewModel 的作用则是,当因系统配置发生改变导致 Activity 重建的时候(比如旋转屏幕),能对 LiveData 进行正确的保存和恢复。仅此而已。LiveData 的使用一般来讲,LiveData 是需要配合 ViewModel 来使用的,但千万不要觉得 LiveData 就一定结合 ViewModel。上面也说道二者只是功能互补。这里为了便于理解,我们先单独学习下 LiveData 的使用。LiveData 的使用分三步:创建一个 LiveData 的实例,让它持有一种特定的数据类型,比如 String 或者 User .通常是将 LiveData 放在ViewModel中使用的(这里我们先单独使用)。创建一个 Observer 对象,并实现其 onChanged(…) 方法,在这里定义当 LiveData 持有的数据发生改变的时候,应该做何操作。可以在这进行UI的更新,一般 Observer 是在 UI controller 中创建,比如 Activity 或者 Fragment 。通过创建的 LiveData 实例的 observe(…)方法,将 Observer 对象添加进 LiveData 中。方法的原型为observe( LifecycleOwner owner, Observer<? super T> observer),第一个参数是 LifecycleOwner对象,这也是 LiveData 能监听生命周期的能力来源。第二个参数就是我们的监听器对象 Observer 。添加 LiveData 和 ViewModel 的依赖: implementation “android.arch.lifecycle:extensions:1.1.1"当然,你也可以分别单独集成 LiveData 和 ViewModel:implementation “android.arch.lifecycle:livedata:1.1.1"implementation “android.arch.lifecycle:viewmodel:1.1.1"接下来就对照上面讲的三步走战略,创建如下代码:public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = “MainActivity”; private MutableLiveData<Integer> mNumberLiveData; private TextView mTvNumber; private Button mBtnStart; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvNumber = findViewById(R.id.tv_number); mBtnStart = findViewById(R.id.btn_start); mBtnStart.setOnClickListener(this); mNumberLiveData = new MutableLiveData<>(); mNumberLiveData.observe(this, new Observer<Integer>() { @Override public void onChanged(@Nullable Integer integer) { mTvNumber.setText(”” + integer); Log.d(TAG, “onChanged: " + integer); } }); } @Override public void onClick(View v) { new Thread() { @Override public void run() { super.run(); int number = 0; while (number < 5) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } number++; mNumberLiveData.postValue(number); } } }.start(); }}这里,我们在 onCreate 方法中创建了一个 MutableLiveData 类型的变量 mNumberLiveData ,并将其泛型指定为 Integer,通过其observe(…)方法把 this 传进去(this为 AppCompatActivity,实现了 LifecycleOwner 接口,支持包为 28.0.0),并传进去一个 Observer,在其onChanged(…)方法中,我们将变化后的数据 integer 设置给 TextView 显示。为了便于观察,我们同时在控制台打印一行对应的日志。Demo 的界面很简单,就是一个按钮,一个 TextView ,点击按钮,开启一个子线程,每过3秒通过postValue(…)修改 LiveData 中的值(如果是在UI线程,可以直接通过 setValue(…)来修改)。这里我们点击开始,并在数字还没变为 5 的时候,就按Home键进入后台,等过一段时间之后,在进入页面,会发现页面最终显示为数字 “5”,但是打印的结果并不是连续的1~5,而是有中断:这也证明了当程序进入后台,变为 inactive 状态时,并不会收到数据更新的通知,而是在重新变为 active 状态的时候才会收到通知,并执行onChanged(…)方法。上面可以看到,我们使用 LiveData 的时候,实际使用的是它的子类 MutableLiveData,LiveData 是一个接口,它并没有给我们暴露出来方法供我们对数据进行修改。如果我们需要对数据修改的时候,需要使用它的具体实现类 MutableLiveData,其实该类也只是简单的将 LiveData 的 postValue(…)和 setValue(…)暴露了出来:public class MutableLiveData<T> extends LiveData<T> { @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); }}MutableLiveData<T>其实是对数据进行了一层包裹。在它的泛型中可以指定我们的数据类。可以存储任何数据,包括实现了 Collections 接口的类,比如 List 。扩展 LiveData有时候我们需要在 observer 的 lifecycle 处于 active 状态时做一些操作,那么我们就可以通过继承 LiveData 或者 MutableLiveData,然后覆写其onActive()和onInactive()方法。这两个方法的默认实现均为空。像下面这样:public class StockLiveData extends LiveData<BigDecimal> { private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); }}LiveData 具有生命周期感知能力,能在 Activity 销毁的时候自动取消监听,这也意味着它可以用来在多个 Activity 间共享数据。我们可以借助单例来实现,这里直接饮用官方 Demo :public class StockLiveData extends LiveData<BigDecimal> { private static StockLiveData sInstance; private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; @MainThread public static StockLiveData get(String symbol) { if (sInstance == null) { sInstance = new StockLiveData(symbol); } return sInstance; } private StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); }}转换 LiveData有时候,我们需要在将 LiveData 中存储的数据分发给 Observer 之前进行一些修改。比如我们例子中拿到的是 Integer 类型的返回值,我们设置进 TextView 的时候,直接使用mTvNumber.setText(integer)会报错,需要使用mTvNumber.setText(”” + integer)这种形式,但我想在这里直接拿到已经处理过的 String 数据,拿到就能直接用,而不需要再在这里手动拼。我们可以通过Transformations类的 map 操作符来实现这个功能。原始的代码为: mNumberLiveData = new MutableLiveData<>(); mNumberLiveData.observe(this, new Observer<Integer>() { @Override public void onChanged(@Nullable Integer integer) { mTvNumber.setText("" + integer); Log.d(TAG, “onChanged: " + integer); } });使用 Transformations.map(…)改造之后的代码: mNumberLiveData = new MutableLiveData<Integer>(); Transformations.map(mNumberLiveData, new Function<Integer, String>() { @Override public String apply(Integer integer) { return "” + integer; } }).observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { mTvNumber.setText(s); Log.d(TAG, “onChanged: " + s); } });这就实现了将一种类型的数据转化为另一种类型的数据。map 操作符会返回一个改造之后的 LiveData,直接对这个 LiveData 进行监听即可。这里的map操作符类似于 RxJava 的map。但有时候我们并不只是需要简单的把数据由一种类型转为另一种类型。我们可能需要的更高级一点。比如,我们一方面需要一个存储 userId 的 LiveData,另一方面又需要维护一个存储 User 信息的 LiveData,而后者的 User 则是根据 userId 来从数据库中查找的,二者需要对应。这时候我们就可以使用Transformations类的switchMap(…)操作符。MutableLiveData<String> userIdLiveData = new MutableLiveData<>();LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, new Function<String, LiveData<User>>() { @Override public LiveData<User> apply(String userId) { // 根据 userId 返回一个 LiveData<User>,可以通过Room来获取 return getUser(userId); }});这里,我们在覆写的apply(…)方法中,每次 userId 发生变化之后,会自动通过 getUser(userId) 去获取一个封装有 User 对象的 LiveData。如果是从数据库获取的话,使用 Google 推出的配套的数据库组件 Room 会比较爽,因为它能直接返回一个 LiveData。关于 Room,有时间的话之后再写文章讲解。从上面可以看出,LiveData 包中提供的 Transformations 非常有用,能让我们的整个调用过程变成链式。但 Transformations 只提供了map(…)和switchMap(…)两个方法,如果我们有其他更复杂的需求,就需要自己通过MediatorLiveData类来创建自己的transformations。话说回来,其实上面两个方法的内部,就是通过MediatorLiveData来实现的,通过 MediatorLiveData 进行了一次转发。这里贴出Transformations的源码:public class Transformations { private Transformations() { } @MainThread public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, Y> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { @Override public void onChanged(@Nullable X x) { result.setValue(func.apply(x)); } }); return result; } @MainThread public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger, @NonNull final Function<X, LiveData<Y>> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(trigger, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = func.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }}源码比较简单,不再详细讲解。它里面其实主要用的就是MediatorLiveData,通过该类我们能组合多个 LiveData 源。当任何一个 LiveData 源发生改变的时候,MediatorLiveData的 Observers 都会被触发,这点比较实用。比如我们有两个 LiveData,一个是从数据库获取,一个是从网络获取。通过MediatorLiveData就能做到,当二者任何一个获取到最新数据,就去触发我们的监听。顺便也贴下MediatorLiveData的源码,它继承自MutableLiveData:public class MediatorLiveData<T> extends MutableLiveData<T> { private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>(); @MainThread public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) { Source<S> e = new Source<>(source, onChanged); Source<?> existing = mSources.putIfAbsent(source, e); if (existing != null && existing.mObserver != onChanged) { throw new IllegalArgumentException( “This source was already added with the different observer”); } if (existing != null) { return; } if (hasActiveObservers()) { e.plug(); } } @MainThread public <S> void removeSource(@NonNull LiveData<S> toRemote) { Source<?> source = mSources.remove(toRemote); if (source != null) { source.unplug(); } } @CallSuper @Override protected void onActive() { for (Map.Entry<LiveData<?>, Source<?>> source : mSources) { source.getValue().plug(); } } @CallSuper @Override protected void onInactive() { for (Map.Entry<LiveData<?>, Source<?>> source : mSources) { source.getValue().unplug(); } } private static class Source<V> implements Observer<V> { final LiveData<V> mLiveData; final Observer<V> mObserver; int mVersion = START_VERSION; Source(LiveData<V> liveData, final Observer<V> observer) { mLiveData = liveData; mObserver = observer; } void plug() { mLiveData.observeForever(this); } void unplug() { mLiveData.removeObserver(this); } @Override public void onChanged(@Nullable V v) { if (mVersion != mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v); } } }}这里顺便提一句,如果想在数据更新的时候让 Observer立即得到通知,也就是说忽略生命周期状态,这时候我们可以使用 LiveData 的observeForever(Observer<T> observer)方法。LiveData 往往是需要结合 ViewModel才能发挥出更大的威力。下面就接着介绍 ViewModel 的知识,以及二者的搭配使用。什么是 ViewModel简单来讲,ViewModel 是一种用来存储和管理UI相关数据的类。但不同的是,它支持在系统配置发生改变的时候自动对数据进行保存。当然,这要配合 LiveData。我们知道,在屏幕旋转的时候,会导致Activity/Fragment重绘,会导致我们之前的数据丢失。就比如,如果我们使用EditText,在里面输入了内容,但是屏幕旋转的时候,会发现其中的text内容被清空了。如果你发现没清空,可能使用的是 support 包下的控件,或者 Activity 继承自 AppCompatActivity,并且给该控件添加了 id。系统对一些简单的数据进行了恢复(其实是在EditText的父类TextView进行的恢复)。对于一些简单的数据,我们可以通过在Activity的 onSaveInstanceState()方法中存储,然后在onCreate()中进行恢复,但是这种方式只适合存储少量的数据,并且是能被序列化和反序列化的数据。而对那些大量的数据则不适用,比如一个 User 或者 Bitmap 的 List。此外,它也使得 View 的数据持有者和 UI controller 逻辑更加分离,便于解耦和测试。LiveData 结合 ViewModel 使用之前我们是单独使用 LiveData,这里配合ViewModel使用:public class MyViewModel extends ViewModel { private MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new MutableLiveData<List<User>>(); loadUsers(); } return users; } private void loadUsers() { // Do an asynchronous operation to fetch users. }}可以看到,这里我们创建一个类,继承自ViewModel,然后在里面存储我们需要的MutableLiveData字段。注意,getUsers()方法返回的类型是LiveData而非 MutableLiveData,因为我们一般不希望在ViewModel 外面对数据进行修改,所以返回的是一个不可变的 LiveData 引用。如果想对数据进行更改,我们可以暴露出来一个setter方法。接下来可以按照如下的方式获取 ViewModel:public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { // Create a ViewModel the first time the system calls an activity’s onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); model.getUsers().observe(this, users -> { // update UI }); }}我们在onCreate()方法中通过ViewModelProviders.of(this).get(MyViewModel.class);这行代码来获取一个MyViewModel实例。之后又通过该实例暴露出来的getter方法获取LiveData 实例。这里要注意,当Activity重建的时候,虽然 onCreate() 方法会重新走一遍,但是这个MyViewModel实例,仍然是第一次创建的那个实例,在ViewModelProviders.of(this).get(***.class)中的get方法中进行了缓存。之后进行源码解析的时候会详细讲解。先看下下面的一张图,了解下 ViewModel 的整个生命周期:ViewModel 最终消亡是在 Activity 被销毁的时候,会执行它的onCleared()进行数据的清理。Fragment 间进行数据共享Fragment 间共享数据比较常见。一种典型的例子是屏幕左侧是一个 Fragment,其中存储了一个新闻标题列表,我们点击一个 item,在右侧的 Fragment 中显示该新闻的详细内容。这种场景在美团等订餐软件中也很常见。通过 ViewModel 将使得数据在各 Fragment 之间的共享变得更加简单。我们需要做的仅仅是在各 Fragment 的 onCreate() 方法中通过:ViewModelProviders.of(getActivity()).get(***ViewModel.class);来获取 ViewModel ,注意,of(…)方法中传入的是二者所在的activity。具体可以参考如下官方代码:public class SharedViewModel extends ViewModel { private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) { selected.setValue(item); } public LiveData<Item> getSelected() { return selected; }}public class MasterFragment extends Fragment { private SharedViewModel model; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 传入 activity model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); itemSelector.setOnClickListener(item -> { model.select(item); }); }}public class DetailFragment extends Fragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 传入 activity SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); model.getSelected().observe(this, { item -> // Update the UI. }); }}Android 3.0 中引入了 Loader 机制,让开发者能轻松在 Activity 和 Fragment 中异步加载数据。但事实上用的人并不多。现在,它几乎可以退出历史舞台了。ViewModel配合Room数据库以及LiveData,完全可以替代Loader,在SDK28里,也越来越多的用Loader也越来越多的被替代。但要注意,ViewModel能用来替换Loader,但是它却并不是设计用来替换onSaveInstanceState(…)的。关于数据持久化以及恢复UI状态等,可以参考下Medium上的这篇文章,讲的简直不能再好了:ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders总结通常 LiveData 是需要配合 ViewModel 使用的。ViewModel 负责在系统配置更改时保存和恢复 LiveData,而 LiveData 则负责在生命周期状态发生改变的时候,对数据的变化进行监听。写到这里算是把 LiveData 和 ViewModel 的使用讲完了。这里我在开篇故意单独把 LiveData 和 ViewModel 分开讲解,相比较官网更加容易理解。但如果想对二者进行详细了解,还是建议把官方文档认真的多阅读几遍。欢迎关注公众号来获取最新消息。 ...

April 14, 2019 · 6 min · jiezi

生命周期组件 Lifecycle 源码解析(二)

上篇文章中我们以继承自 AppCompactActivity 这种情况来分析 Lifecycle 的源码。本篇,我们将一起来分析下继承自普通 Activity 这种情况下的源码分析。support library 27.0.0与 28.0.0 下使用的区别之前说道,我们如果不继承自 AppCompactActivity ,就只能自己手动在各 Activity 的生命周期方法中调用 markState(…) 函数来进行生命周期事件的分发。类似下图:但是如果你是用的是 27.0.0 版本的 support library ,你会发现你这样实现的话是没有效果的。你还需要自己再手动调用 LifecycleRegistry 类的handleLifecycleEvent(…)方法。因为 support library 27.0.0 下引入的 Lifecycle 的 common 库的版本是 1.0.0(引入的 runtime 库会自动引入 common 等库),而 28.0.0版本引入的则是 1.1.1,二者的实现是有差别的,可以看下下面的源码。先来看1.1.1版本下实现:再来看下1.0.0版本下实现:可以看出,在 1.0.0 版本中,markState()方法,仅仅是对 State 进行了赋值,而没有对事件进行分发,而在 1.1.1 版本中则是在标记 State 的时候,同时进行事件的分发。这就不用我们再像之前那样写那一行繁琐的代码,还要去根据生命周期方法来判断传进去什么 Event 作为参数。那我们本篇所讲的继承自普通 Activity 情况下的源码解析,就是这个?当然不是。如果是这个,那就没有必要再讲了,因为这些在上篇中已经讲过了。继续往下看。引入 extensions 库之后的源码解析虽然通过重写 Activity 生命周期,并通过在各方法中仅添加一行mLifecycleRegistry.markState()代码就能实现生命周期的感知。但是,作为推动社会发展的“懒人” – 程序员,自然想通过更简单的方式来解放右手。办法总比困难多。从上一篇文章我们知道,通过继承 AppCompactActivity 这种实现方式中核心就是向 Activity 中注入一个空的 Fragment–ReportFragment。我们能不能也通过这种方式,动态的向 Activity 中注入这个 ReportFragment 呢?我当时是这么想的。之前阅读8.1的系统源码的时候,了解到能通过 Application 的registerActivityLifecycleCallbacks() 方法监听 Activity 的生命周期。说明这条路是可行的。当然,我们没必要自己进行实现,因为 Google 已经帮我们实现了。Google 为我们提供了一个extensions库,我们需要单独引入:implementation “android.arch.lifecycle:extensions:$lifecycle_version"该库同时也会自动引入 LiveData 和 ViewModel 相关库,关于这二者,我们之后的文章中会另行讲解。引入该库之后,我们的使用方式,就跟继承自 AppCompactActivity 基本相同,唯一的不同点就是我们需要自己实现 LifecycleOwner :引入该库之后,我们Command/Ctrl+鼠标左键,点击ReportFragment,会发现使用到它的有两个类:LifecycleDispatcher.java 和 ProcessLifecycleOwner.java这两个类,而这二者,就是android.arch.lifecycle:extensions:1.1.0这个库下的类:那我们就先追踪ReportFragment.injectIfNeededIn(activity);在LifecycleDispatcher.java类中的调用:ReportFragment.injectIfNeededIn(activity); 这行代码是在 LifecycleDispatcher 的静态内部类DispatcherActivityCallback的 onActivityCreated(…) 方法中调用的。而DispatcherActivityCallback又继承自EmptyActivityLifecycleCallbacks,EmptyActivityLifecycleCallbacks是啥?它其实就是Application.ActivityLifecycleCallbacks接口的空实现类。看到这就对上了,原来 Google 采用的就是我们前面提到的方式,通过Application.ActivityLifecycleCallbacks进行监听。继续回到上面的 LifecycleDispatcher 的源码查看,发现静态内部类 DispatcherActivityCallback 的实例化是在LifecycleDispatcher类的static方法init()中,在该方法中进行监听器的注册:这里面,就真正的看到了通过Application的registerActivityLifecycleCallbacks来注册监听器。继续追踪 LifecycleDispatcher#init(…)方法,就进入了ProcessLifecycleOwnerInitializer类的onCreate()方法:在其 onCreate() 方法中,进行了LifecycleDispatcher 的初始化,并且也进行了ProcessLifecycleOwner 的初始化。关于ProcessLifecycleOwner ,这里我们简单点下,它也实现了 LifecycleOwner 接口,主要用来监听应用的前后台切换。回过来继续看ProcessLifecycleOwnerInitializer,它继承自 ContentProvider ,也就是说,它是个 ContentProvider ,但通过看源码,发现它对 ContentProvider 的各种方法都进行了空实现。其实,这里就是利用了 ContentProvider 的隐式加载。它的 onCreate() 方法执行时机是在Application 的 onCreate()方法之前。这样它就能通过 Application 来监听 Activity 的创建,并判断是否已经添加过了一个空UI的 ReportFragment。若没有,就进行添加。这种设计真的是太妙了。我们知道,四大组件都是要在 AndroidManifest.xml 文件中进行生命的。那这个 ContentProvider 类型的 ProcessLifecycleOwnerInitializer 又是在什么时候声明的呢?我们找到extensions库,通过如下方式查看它的下载位置:然后打开这里的AndroidManifest.xml,会发现,在这里进行了声明。这里的AndroidManifest.xml最终会合并入我们app module 的AndroidManifest.xml文件中。至此,我们就对 Lifecycle 的源码进行了完全的解析。包括继承自普通 Activity 和继承自AppCompactActivity这两种情况。补充这里,再进行一点补充。如果我们使用的是 Java8,我们可以通过依赖下面这个库,来避免使用@OnLifecycleEvent(…)注解的方式进行生命周期回调方法的声明:implementation “android.arch.lifecycle:common-java8:1.1.1"这个库其实就一个 DefaultLifecycleObserver.java 接口类。之后我们需要 LifecycleObserver 的时候,一般实现 DefaultLifecycleObserver 接口即可(不用再去直接实现 LifecycleObserver 接口),使用方式变成了下面这样:可以看到,这里我们直接在覆写的生命周期对应回调方法中写入我们的逻辑代码即可。更加简洁。后续文章会继续讲 LiveData 及 ViewModel 等Architecture Components,欢迎关注公众号类获取最新消息。 ...

April 14, 2019 · 1 min · jiezi

生命周期组件 Lifecycle 源码解析(一)

在上篇文章:Android 生命周期组件 Lifecycle 使用详解 中,我们讲了 Lifecycle 的简单使用,本篇我们来研究下它的源码。基础环境搭建首先,按照上篇文章所讲,快速搭建环境。添加 Lifecycle 轻量级依赖库: implementation “android.arch.lifecycle:runtime:1.1.1"添加support library 28.0.0的支持库(希望大家能先保持一致,因为不同版本的源码是有区别的,后面会将到):implementation ‘com.android.support:appcompat-v7:28.0.0’再添加个注解处理器相关的依赖,至于用处,后面会讲:annotationProcessor “android.arch.lifecycle:compiler:1.1.1"接下来创建实现了 LifecycleObserver 接口的 MyObserver 类:让我们的 Activity 继承自 AppCompatActivity,并在 onCreate() 方法中通过 getLifecycle().addObserver(new MyObserver())绑定 MyObserver :核心代码就一句, getLifecycle().addObserver(new MyObserver()),就能让我们创建的 MyObserver 类,拥有生命周期感知能力。我们知道,这里主要的对象就两个。一个是 getLifecycle() 方法返回来的 LifecycleRegistry 对象(继承自抽象类 Lifecycle),一个是我们创建的需要监听生命周期的类 MyObserver。那我们不禁要问:LifecycleRegistry 是如何感知到生命周期的?它又是如何把生命周期事件分发给 LifecycleObserver 的?我们先来解决第一个问题,LifecycleRegistry 是如何感知到生命周期的。LifecycleRegistry 是如何感知到生命周期的首先,我们Command/Ctrl + 鼠标左键跟踪 getLifecycle() 代码,发现它的具体实现是在 AppCompatActivity 的祖先类 SupportActivity 中,该类实现了 LifecycleOwner 接口。在 onSaveInstanceState() 方法中将 mLifecycleRegistry 的状态置为了 Lifecycle.State.CREATED,这点我们在前篇也讲到过。但从这我们还是看不到跟生命周期有关的东西。此时,我们发现在 onCreate() 方法中有这一行代码:ReportFragment.injectIfNeededIn(this);ReportFragment 是做什么的?点进去看:可以看到, ReportFragment 的 injectIfNeededIn(Activity activity)方法向 Activity 中添加了一个未设置布局的 Fragment :然后又在重写的生命周期事件中调用dispatch(Lifecycle.Event event)方法,来分发生命周期事件,这就是“生命周期感知能力”的来源。这种通过一个空的 Activity 或者 Fragment 来实现特定功能的技巧还是挺常见的,比如权限请求库 RxPermission ,以及 airbnb 开源的用于URL跳转的 DeepLinkDispatch(前者是使用空的 Fragment,后者使用的是空的 Activity)ReportFragment#dispatch(Lifecycle.Event event) 这里面,又调用了 LifecycleRegistry 的handleLifecycleEvent(event)方法。至此,就引入了第二个问题,事件是如何分发到 LifecycleObserver 的。事件是如何分发到 LifecycleObserver 的进入 LifecycleRegistry#handleLifecycleEvent(Lifecycle.Event event)方法,发现它又调用了 moveToState(State next) 方法:而在 sync() 方法中,根据 state 的状态,最终会调用到backwardPass(…)或者forwardPass(…):以 forwardPass(…) 为例:上图可以看到,通过 mObserverMap 最终获取到一个 ObserverWithState 类型的 observer 对象,并调用它的dispatchEvent进行事件分发: observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));ObserverWithState 又是个什么鬼?我们继续追踪,发现 ObserverWithState 是 LifecycleRegistry 的一个静态内部类。从名称上就能看出,该类封装了 Observer 对象和 State 对象(具体就是 State 和 GenericLifecycleObserver,GenericLifecycleObserver 是个接口,继承自 LifecycleObserver),在其 dispatchEvent 方法中,最终会回调 mLifecycleObserver 的 onStateChanged(…) 方法。追踪到这里,我们知道了,Lifecycle在监听到生命周期变化之后,最终会回调 GenericLifecycleObserver 的 onStateChanged() 方法。我们不由得疑惑,我们定义的 MyObserver 哪去了?没看到有调用我们定义的回调方法啊。它和 GenericLifecycleObserver 又有什么关系?我们看到,ObserverWithState 的构造函数里传进来了一个 LifecycleObserver 类型的 observer 对象,这个参数是从哪传进来的?继续追踪,发现追到了LifecycleRegistry#addObserver(LifecycleObserver observer)方法。而这个方法,就是我们在MainActivity#onCreate(…)方法中调用的: getLifecycle().addObserver(new MyObserver());到这里,总算跟我们的 MyObserver 关联上了。查看LifecycleRegistry#addObserver(LifecycleObserver observer)方法源码:这里面的核心代码就两行,一行是: ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);这行代码,通过传进来的Observer对象,创建出 ObserverWithState 对象。还有一行是: ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);这行代码是将 LifecycleObserver 对象放入一个FastSafeIterableMap 中,以便进行迭代。接下来我们就进入 ObserverWithState 的构造方法中看看:在构造方法中,通过 Lifecycling.getCallback(observer)根据传进来的 observer ,构造了一个 GenericLifecycleObserver 类型的 mLifecycleObserver ,那秘密应该也就在这个方法里,继续跟进。这个方法的本质,其实就是根据传进来的一个LifecycleObserver 对象,构造出来一个 GenericLifecycleObserver 对象(目前有四个子类:FullLifecycleObserverAdapter、SingleGeneratedAdapterObserver、CompositeGeneratedAdaptersObserver、ReflectiveGenericLifecycleObserver),而最终构造出来的对象,就包含了我们创建的 LifecycleObserver 的所有信息,包括各种回调方法等。看到这里,就要提到文章开头要大家添加的一个注解处理器的依赖:annotationProcessor “android.arch.lifecycle:compiler:1.1.1"当我们通过注解的方式来自定义LifecycleObserver 的时候,按照传统方式,必定要通过反射来对注解进行解析,这样就会对性能造成影响。一方面,我们通过缓存,来避免每次都通过反射获取构造器。另一方面,又通过注解处理器,在编译时对那些被@OnLifecycleEvent注解标注的普通方法,进行预处理,生成以“类名_LifecycleAdapter”命名的类,将各种回调方法直接进行逻辑转换,避免反射,进而来提高性能。明白了这点,再看Lifecycling.getCallback(observer)方法就比较容易理解了。如果传进来的的参数 object 是 FullLifecycleObserver 类型,就把它构造成FullLifecycleObserverAdapter 对象,并返回如果传进来的的参数 object 是GenericLifecycleObserver类型,直接返回该对象如果1,2都不满足,就解析该类的的构造器的Type(该类是反射获取的,还是通过注解处理器生成的)。如果是通过注解处理器生成的类来调用回调函数,就返回一个SingleGeneratedAdapterObserver/CompositeGeneratedAdaptersObserver 对象如果以上条件都不满足,就通过反射来调用各回调函数。返回一个 ReflectiveGenericLifecycleObserver 对象现在我们在 app 目录下的 bulid.gradle 中添加上上面的注解处理器依赖,然后编译下项目,会发现在build目录下生成了对应的类:MyObserver_LifecycleAdapter.java点进去,看看生成的这个类的源码:可以看到,我们在 MyObserver 中通过@OnLifecycleEvent注解标注的那些方法,在这里都根据条件进行判断了,而非通过注解。这时候我们就能理清这个这个流程了,当添加了注解处理器之后,我们这里的Lifecycling.getCallback(observer)方法将会把我们的MyObserver对象构建成一个 SingleGeneratedAdapterObserver对象返回(因为这里只有一个构造器),之后的 mLifecycleObserver.onStateChanged(owner, event);其实调用的就是SingleGeneratedAdapterObserver的onStateChanged(owner, event)方法:这里面就可以看到,它调用了内部包裹的类的callMethods(…)方法,也就是我们上面提到的MyObserver_LifecycleAdapter的callMethonds(…)方法。到这里,就完成了 Lifecycle 源码的解析。通过反射获取注解信息这顺便提下通过注解的方式调用各回调方法的过程。主要相关类就是 ReflectiveGenericLifecycleObserver.java这里我们主要关注回调信息 CallbackInfo 的获取方式的代码: mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());因为反射的代价是比较大的,所以又通过 ClassesInfoCache.java这个单例类,为 ReflectiveGenericLifecycleObserver 类要调用的各种方法的相关信息进行了缓存。点进去看下它的 getInfo(…) 方法内部,是如何获取方法信息的。里面又调用了createInfo()方法:这里,就能看到对注解进行处理的代码了。到这,我们就算完成了继承自 AppCompactActivity 的情况下的源码解析,而继承自普通 Activity 这种情况下,原理是什么呢?鉴于篇幅,将放在下篇文章。欢迎关注我的公众号获取。 ...

March 5, 2019 · 2 min · jiezi

Android 生命周期组件 Lifecycle 使用详解

前言2018 年的 Google I/O 大会上,Google 发布了 Android Jetpack,并称其为下一代的 Android 组件,旨在帮助开发者加快应用开发速度。准确来讲,Jetpack 是一系列 Android 软件组件的集合,它包括基础组件、架构组件、行为组件、界面组件。其中的 Android Architecture Components 指的就是这里的 “架构组件”。Android Architecture Components 是 Google 推荐的一个构建 APP 的应用架构,它包含了一些列架构相关组件。而本篇文章我们要介绍的 Lifecycle 就是其中的一个与生命周期相关的库,同时,Lifecycle 也跟 LiveData 和 ViewModel 两个库紧密联系,想要搞懂后两者,就必须先搞懂它。具体各组件之间的关系,以及各自在 Jetpack 中的地位,可以参见下面两幅来源于官网的图片。Lifecycle 的作用Lifecycle 是具有生命周期感知能力的组件,也就是说,我们能在 Activity 或者 Fragment 的生命周期发生变化的时候得到通知。我们往往会在 Activity 的各种生命中周期方法里执行特定的方法,比如,进行广播的注册和解绑、Eventbus 的注册和解绑等:public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); } @Override protected void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override protected void onDestroy() { EventBus.getDefault().unregister(this); super.onDestroy(); }}如果我们把很多这种需要跟生命周期相关的逻辑代码都直接放在 Activity 的生命周期方法中,Activity 将会变得难以维护。通过 Lifecycle,我们就能通过把这些逻辑抽离出来,进而避免这种问题。因为本质上我们需要的只是 Activity 或者 Fragment 的生命周期发生改变的时候能通知到我们,以便我们在对应生命周期中执行对应的方法。Lifecycle 的基本使用2.0、 导入 Lifecycle 依赖Lifecycle 被包含在 support library 26.1.0 及之后的依赖包中,如果我们的项目依赖的支持库版本在 26.1.0及以上,那么不需要额外导入 Lifecycle 库,本篇例子中使用的支持库是 28.0.0 : implementation ‘com.android.support:appcompat-v7:28.0.0’如果支持库版本小于 26.1.0 ,就需要单独导入 Lifecycle 库 : implementation “android.arch.lifecycle:runtime:1.1.1"当然,如果项目已经迁移到了 AndroidX,可以使用下面的方式引入 : implementation “androidx.lifecycle:lifecycle-runtime:2.0.0"还是建议大家尝试尽快把项目迁移为 AndroidX,因为很多更新,会最先在 AndroidX 中发布,逐渐摆脱传统的support包。比如这里要讲的 Lifecycle 在 AndroidX 中已经升级到了 2.x 版本,而支持库中还是 1.x 版本。鉴于支持库一般都在 26.1.0 以上,并且尚有大部分用户未迁移到AndroidX,在本篇文章中,我们使用 support library 28.0.0 中默认包含的 Lifecycle 库。我们在项目的 app 目录下的 build.gradle 文件中添加以下依赖: implementation ‘com.android.support:appcompat-v7:28.0.0’以 support library 版本在 26.1.0 及以上为前提,这里我们分两种情况来讲。一种是我们创建的Activity 继承自 AppCompatActivity(以Activity 为例,Fragment类似),另一种是创建的 Activity 继承自普通的 Activity,而非 AppCompatActivity。这里要先说一点, Lifecycle 的实现机制是观察者模式,意识到这点,再讲它的使用过程及原理就比较容易理解了。 整体流程:构建一个 Lifecycle 对象(通过一个实现了 LifecycleOwner 接口的对象的 getLifecycle()方法返回),这个对象就是一个被观察者,具有生命周期感知能力构建一个 LifecycleObserver 对象,它对指定的 Lifecycle 对象进行监听通过将 Lifecycle 对象的 addObserver(…) 方法,将 Lifecycle 对象和 LifecycleObserver 对象进行绑定2.1、 方式一:继承自 AppCompatActivity首先,我们创建一个 MyObserver.java 类,让它实现 LifecycleObserver 接口( LifecycleObserver 接口是一个空接口,主要是给注解处理器使用),如下:public class MyObserver implements LifecycleObserver { private static final String TAG = “MyObserver”; // 使用注解 @OnLifecycleEvent 来表明该方法需要监听指定的生命周期事件 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void connectListener() {// … Log.d(TAG, “connectListener: ——– onResume” ); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void disconnectListener() {// … Log.d(TAG, “disconnectListener: ——- onPause”); }}可以看到,我们通过在方法上使用@OnLifecycleEvent 注解使得该方法具有了生命周期感知能力。括号里面的参数,表明需要监听的是什么生命周期事件。Lifecycle 主要就是通过 Event 和 State 这两个枚举类来跟踪所关联组件的生命周期状态。具体的 Event 和 State 之间的转换关系,可以参照下图:接下来,让我们的 Activity 继承自 AppCompatActivity,然后在 onCreate(…) 方法中通过getLifecycle().addObserver(new MyObserver())完成 Lifecycle 和LifecycleObserver 的绑定。public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 就只需要这一行代码,简洁吧 getLifecycle().addObserver(new MyObserver()); }}然后我们就可以运行下程序,跑起来之后按 Home 键或者按返回键进行操作。能看到,随着生命周期的变化,MyObserver() 中定义的方法在控制台中也被正确地打印了出来。是不是觉得特别简单。但之所以毫不费力,是因为有人替你“负重前行”。在 support library 26.1.0 及以后的支持库中,AppCompatActivity 的祖先类 SupportActivity已经默认实现了 LifecycleOwner 接口,通过其 getLifecycle() 方法可以直接返回一个 Lifecycle 对象。之后我们就可以通过该对象的 addObserver(…) 方法将 Lifecycle 跟指定的 LifecycleObserver 进行绑定。2.2、 方式二:继承自普通的 Activity首先,我们仍然需要像上面的方式,来创建一个MyObserver 对象。这次我们创建一个继承自普通的 Activity 的 Activity ,那自然无法直接使用 getLifecycle() 方法来获取 Lifecycle 。无法直接使用,那我们能否模仿 AppCompatActivity的实现,来自己创建 Lifecycle 对象呢?当然可以。这时候,我们就需要自己实现LifecycleOwner接口,并在具体的生命周期下通过 LifecycleRegistry 的 markState(…)方法来主动进行事件的分发。请看下面改造过的 MainActivity.java 代码 :public class MainActivity extends Activity implements LifecycleOwner { private LifecycleRegistry mLifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLifecycleRegistry = new LifecycleRegistry(this); getLifecycle().addObserver(new MyObserver()); mLifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override protected void onResume() { super.onResume(); mLifecycleRegistry.markState(Lifecycle.State.RESUMED); } @Override protected void onPause() { super.onPause(); mLifecycleRegistry.markState(Lifecycle.State.STARTED); } @NonNull @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; }}然后运行代码,发现结果和上面的完全一样。可以看到,MainActivity实现了LifecycleOwner接口(实现该接口的对象,即是 Lifecycle 的持有者),并在其 getLifecycle( ) 方法中返回了一个 LifecycleRegistry对象,而 LifecycleRegistry 是 Lifecycle 的实现类,能处理多个 Observer,我们自定义 LifecycleOwner的时候就可以直接使用它。其他使用方式,则完全相同。为了让使用更加方便灵活,Lifecycle 还提供了查询当前组件所处的生命周期状态的方法:lifecycle.getCurrentState().isAtLeast(STARTED)总结实现了 LifecycleObserver 接口的类可以和实现了 LifecycleOwner 接口的类无缝工作,因为 LifecycleOwner 可以提供一个 Lifecycle 对象,而 LifecycleObserver 就正需要对这个 Lifecycle 对象进行监听呢。LifecycleOwner 是从特定的类(比如 Activity 或者 Fragment 等)中抽象出来的Lifecycle 的持有者。LifecycleRegistry 是 Lifecycle 的实现类,用于注册和反注册那些需要监听当前组件生命周期的 LifecycleObserver注意从 1.0.0-rc1 版本的 Lifecycle 包开始,当 Activity 的 onSaveInstanceState() 方法调用结束之后,Lifecycle 将立刻被标记为 CREATED 和 ON_STOP ,而不是等 onStop() 方法调用结束。这点和 API level 26 或者更低版本上 Activity 的生命周期的调用顺序并不匹配,需要稍加注意。有具体需求的可以进一步查阅相关文档。更多最新消息,欢迎关注我的公众号获取: ...

February 28, 2019 · 2 min · jiezi