Architecture Components 知识梳理(1)
一、概述
听说这一套ToolKit
已经有很长一段时间了,一直没有系统的学习过,前几天有同事在项目中通过Lifecycles
解决了监听Activity
生命周期的问题,不得不说,真的是一套强大的框架,除此之外,前段时间Google
还更新了Navigation
、Paging
和WorkManager
用来解决 页面的管理 以及 任务的调度 问题,更激发了我学习的动力。
依照惯例,先从最基本的Demo
学起,然后再去分析源码。
二、导入依赖
在 根目录 的build.gradle
文件中,加上google()
的远程仓库声明(现在AS
创建的工程已经默认包含了该声明)。
allprojects {
repositories {
jcenter()
//加上这一句。
google()
}
}
当我们使用了'com.android.support:appcompat-v7:27.1.1'
时,其实已经默认导入了lifecycles
相关的库,由此可见,这确实是之后的一个趋势。
如果我们没有使用support:appcompat
,那么就需要自己去声明依赖,当然并不是说要导入全部的依赖,而是可以根据需要去选择对应的依赖库,具体的说明在注释中。
- 选择仅导入
LiveData
、ViewModel
、Lifecycles
的其中一种,或者全部导入。 - 注解处理器,在
Java8
上使用common-java8
,在Java8
以下使用compiler
。 - 流式处理支持库
reactivestreams
- 测试支持库
core-testing
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin
// alternatively - just LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData), Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "android.arch.core:core-testing:$lifecycle_version"
}
这里,我们直接使用appcompat
当中导入的组件即可。
三、Lifecycle
3.1 解决的问题
在Android
开发当中,生命周期 是一个很重要的东西,因为我们往往需要在页面创建onCreate
、页面展示onResume
,和页面销毁onDestroy
的时候,去进行业务逻辑的处理,而在此之前,我们只能通过Activity
和Fragment
才能收到生命周期的回调,而其它的组件,例如Fragment
当中的View
需要收到生命周期的回调,那么只能通过Activity
或Fragment
去通知它,这就造成了很多冗余的代码,特别是当我们期望提供一个View
作为SDK
给接入方时,又无形中增加了接入方的成本。
如果任何一个对象,通过观察者的方式,能够收到Activity/Fragment
生命周期的各种回调就好了。没错!Lifecycle
就是这么一个东西!
3.2 示例
- 首先,我们定义一个类
LiveObserver
,该类 实现 了LifecycleObserver
接口,它定义了一系列的方法并用@OnLifecycleEvent(Lifecycle.Event.xxx)
进行修饰,Lifecycle.Event
的可选类型有如下几种,很明显可以看出是生命周期相关的东西。
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
在这些方法中添加Log
用于调试:
public class LiveObserver implements LifecycleObserver {
private static final String TAG = LiveObserver.class.getSimpleName();
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate() {
Log.d(TAG, "onCreate()");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart() {
Log.d(TAG, "onStart()");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume() {
Log.d(TAG, "onResume()");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause() {
Log.d(TAG, "onPause()");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop() {
Log.d(TAG, "onStop()");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy() {
Log.d(TAG, "onDestroy()");
}
}
- 第二步,编写测试的
Demo
,注意,这里我们是通过AppCompatActivity
提供的getLifecycle#addObserver
方法来实现对第一步中的LiveObserver
实例进行监听的:
public class LiveAppCompactActivity extends AppCompatActivity {
private Button mBtnBind;
private Button mBtnUnBind;
private LifecycleObserver mObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_appcompact);
mBtnBind = findViewById(R.id.bt_bind);
mBtnBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mObserver == null) {
mObserver = new LiveObserver();
getLifecycle().addObserver(mObserver);
}
}
});
mBtnUnBind = findViewById(R.id.bt_unbind);
mBtnUnBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mObserver != null) {
getLifecycle().removeObserver(mObserver);
mObserver = null;
}
}
});
}
}
3.3 模拟场景
场景一:点击绑定按钮
当界面完全可见的时候,我们点击“绑定”按钮,Log
输出为:
场景二:点击绑定按钮,点击解绑按钮
没有任何输出。
场景三:再次点击绑定按钮
再次点击绑定按钮场景四:在绑定状态下,锁屏或者按 Home 回到桌面
锁屏或按 Home 回到说面场景五:解锁或者点击图标重新进入
解锁或者点击图标重新进入场景六:按 Back 回到桌面
按 Back 回到桌面场景结论
- 在 第一次绑定 的时候,
LifeObserver
会从onCreate()
方法依次回调到Activity
当前所处的生命周期状态。 -
解绑 不会触发任何生命周期回调,之后也收不到
Activity
的任何通知。 - 在绑定过后,
LifeObserver
会跟随着Activity
的生命周期变化。
3.4 不使用 AppCompactActivity 实现
假如我们使用的不是AppCompactActivity
,那么要怎么达到和3.2
中一样的效果呢,实现方式如下:
- 让普通的
Activity
实现LifecycleOwner
接口 - 在其内部创建一个
LifecycleRegistry
对象,其构造函数参数为实现了LifecycleOwner
接口的Activity
,getLifecycle()
方法返回该对象。 - 通过
LifecycleRegistry#addObserver
注册观察者LiveObserver
。
整体的实现代码如下所示:
/**
* 1.需要让 Activity 实现 LifecycleOwner 接口。
*/
public class LiveActivity extends Activity implements LifecycleOwner {
private Button mBtnBind;
private Button mBtnUnBind;
//2.创建 mLifecycleRegistry 对象,其构造函数为实现了 LifecycleOwner 的对象。
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
private LifecycleObserver mObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live);
mBtnBind = findViewById(R.id.bt_bind);
mBtnBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mObserver == null) {
mObserver = new LiveObserver();
//4.1 注册的方法和之前相同。
getLifecycle().addObserver(mObserver);
}
}
});
mBtnUnBind = findViewById(R.id.bt_unbind);
mBtnUnBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mObserver != null) {
//4.2 反注册的方法和之前相同。
getLifecycle().removeObserver(mObserver);
mObserver = null;
}
}
});
}
/**
* 3.该函数返回 mLifecycleRegistry。
*
* @return 返回 mLifecycleRegistry。
*/
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
其效果和之前3.3
中的表现是一致的。
四、实现原理
有没有感到很神奇,我们是怎么让一个独立的对象和Activity/Fragment
的生命周期关联起来的呢。通过源码我们可以发现,有以下两个类实现了LifecycleOwner
接口:
android.support.v4.app.SupportActivity
@RestrictTo(LIBRARY_GROUP)
public class SupportActivity extends Activity implements LifecycleOwner {
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
android.support.v4.app.Fragment
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
ViewModelStoreOwner {
LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
当我们分析完之后,会发现这两种使用的是不同的方式来实现我们最终看到的效果的。
4.1 使用 Activity 的 getLifecycle 注册
当我们使用SupportActivity
的getLifecycle()
,其实系统在Activity
启动的时候 偷偷 地为我们添加了一个没有界面的ReportFragment
。
@RestrictTo(LIBRARY_GROUP)
public class SupportActivity extends Activity implements LifecycleOwner {
@Override
@SuppressWarnings("RestrictedApi")
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在 onCreate 方法当中偷偷地添加。
ReportFragment.injectIfNeededIn(this);
}
}
用过Fragment
的同学们都知道,Fragment
的生命周期是和它所在的Activity
绑定的,那么当Activity
的状态变化时,Fragment
的生命周期就会被回调,我们来看一下ReportFragment
是怎么处理的:
public class ReportFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
//这里会去分发事件。
dispatch(Lifecycle.Event.ON_RESUME);
}
private void dispatch(Lifecycle.Event event) {
Activity activity = getActivity();
//这里的 activity 就是我们上面的 SupportActivity,而 getLifecycle 就返回了 LifecycleRegistry 对象。
if (activity instanceof LifecycleOwner) {
Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
if (lifecycle instanceof LifecycleRegistry) {
((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
}
}
}
}
接着,就会走到LifecycleRegistry
的handleLifecycleEvent
方法当中,具体的逻辑如下所示,最终会通知到它内部所持有的LifecycleObserver
:
public class LifecycleRegistry extends Lifecycle {
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
//获取下一步的状态。
State next = getStateAfter(event);
//转移到该状态。
moveToState(next);
}
private void moveToState(State next) {
if (mState == next) {
return;
}
mState = next;
if (mHandlingEvent || mAddingObserverCounter != 0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;
//状态同步。
sync();
mHandlingEvent = false;
}
private void sync() {
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "
+ "new events from it.");
return;
}
while (!isSynced()) {
mNewEventOccurred = false;
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
//1.向后转移。
backwardPass(lifecycleOwner);
}
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
//2.向前转移
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
private void forwardPass(LifecycleOwner lifecycleOwner) {
Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
mObserverMap.iteratorWithAdditions();
while (ascendingIterator.hasNext() && !mNewEventOccurred) {
Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
ObserverWithState observer = entry.getValue();
while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
pushParentState(observer.mState);
//这里的 observer 就是我们通过 addObserver 加入的监听者,它会根据回调的状态和注解去调用对应的方法。
observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
popParentState();
}
}
}
}
整个状态的传递如下图所示:
状态传递最后,让我们用断点验证一下之前的分析,以onResume
为例:
4.2 使用 Fragment 的 getLifecycle 注册
下面我们再来分析Fragment
的实现过程,Fragment
的实现就简单多了,它是直接在对应的生命周期里,通过内部持有的LifecycleRegistry
对象调用的,很好理解:
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
ViewModelStoreOwner {
void performResume() {
//简单粗暴,直接通过内部持有的对象调用。
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
}
之后handleLifecycleEvent
的过程就和4.1
中一致了,就不过多分析了,大家只需要了解基本的思想就好了,不必过于深究源码。
五、使用 Lifecycle 应该注意什么
在 https://developer.android.google.cn/topic/libraries/architecture/lifecycle 中提到了下面两点,属于对lifecycle
组件的总结,但是很多东西,我们还没有学到,因此先留下原文,等学习完后几章的内容后,再来理解。
Best practices for lifecycle-aware components
Use cases for lifecycle-aware components
5.1 Best practices for lifecycle-aware components
- Keep your UI controllers (activities and fragments) as lean as possible. They should not try to acquire their own data; instead, use a
ViewModel
to do that, and observe aLiveData
object to reflect the changes back to the views. - Try to write data-driven UIs where your UI controller’s responsibility is to update the views as data changes, or notify user actions back to the
ViewModel
. - Put your data logic in your
ViewModel
class.ViewModel
should serve as the connector between your UI controller and the rest of your app. Be careful though, it isn'tViewModel
's responsibility to fetch data (for example, from a network). Instead,ViewModel
should call the appropriate component to fetch the data, then provide the result back to the UI controller. - Use
Data Binding
to maintain a clean interface between your views and the UI controller. This allows you to make your views more declarative and minimize the update code you need to write in your activities and fragments. If you prefer to do this in the Java programming language, use a library likeButter Knife
to avoid boilerplate code and have a better abstraction. - If your UI is complex, consider creating a
presenter
class to handle UI modifications. This might be a laborious task, but it can make your UI components easier to test. - Avoid referencing a
View
orActivity
context in yourViewModel
. If theViewModel
outlives the activity (in case of configuration changes), your activity leaks and isn't properly disposed by the garbage collector.
5.2 Use cases for lifecycle-aware components
- Switching between coarse and fine-grained location updates. Use lifecycle-aware components to enable fine-grained location updates while your location app is visible and switch to coarse-grained updates when the app is in the background.
LiveData
, a lifecycle-aware component, allows your app to automatically update the UI when your user changes locations. - Stopping and starting video buffering. Use lifecycle-aware components to start video buffering as soon as possible, but defer playback until app is fully started. You can also use lifecycle-aware components to terminate buffering when your app is destroyed.
- Starting and stopping network connectivity. Use lifecycle-aware components to enable live updating (streaming) of network data while an app is in the foreground and also to automatically pause when the app goes into the background.
- Pausing and resuming animated drawables. Use lifecycle-aware components to handle pausing animated drawables when while app is in the background and resume drawables after the app is in the foreground.
六、参考文章
(1) Handling lifecycles with lifecycle-aware components
(2) Android 官方架构组件 Lifecycle 详解 & 原理分析
(3) Android 架构组件(一)——Lifecycle