一、概述
聽說這一套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 回到桌面
場景五:解鎖或者點擊圖標重新進入
場景六:按 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