[TOC]
使用生命周期感知組件處理生命周期
生命周期的組件執(zhí)行動作以響應(yīng)另一個組件生命周期狀態(tài)的變化,比如activities和fragments。這些組件可以幫助您生成更有組織、更輕量級、更易于維護的代碼。
一種常見模式是在activities和fragments的生命周期方法中實現(xiàn)依賴組件的操作。但是,這種模式導(dǎo)致代碼組織不良和錯誤擴散。通過使用生命周期感知組件,您可以將依賴組件的代碼移出生命周期方法并移入組件本身。
android.arch.lifecycle 軟件包提供了類和接口,使您可以構(gòu)建生命周期感知 組件 - 這些組件可以根據(jù)activities或fragments的當(dāng)前生命周期狀態(tài)自動調(diào)整其行為。
注意:要導(dǎo)入 android.arch.lifecycle 到Android項目中,請參閱Lifecycle發(fā)行說明中有關(guān)聲明依賴項的說明。
Android框架中定義的大多數(shù)應(yīng)用程序組件都附加了生命周期。生命周期由操作系統(tǒng)或流程中運行的框架代碼管理。它們是Android運作方式的核心,您的應(yīng)用程序必須尊重它們。不這樣做可能會觸發(fā)內(nèi)存泄漏甚至應(yīng)用程序崩潰。
假設(shè),我們有一個活動,在屏幕上顯示設(shè)備位置。常見的實現(xiàn)可能如下所示:
class MyLocationListener {
public MyLocationListener(Context context, Callback callback) {
// ...
}
void start() {
// connect to system location service
}
void stop() {
// disconnect from system location service
}
}
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
@Override
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, (location) -> {
// update UI
});
}
@Override
public void onStart() {
super.onStart();
myLocationListener.start();
// manage other components that need to respond
// to the activity lifecycle
}
@Override
public void onStop() {
super.onStop();
myLocationListener.stop();
// manage other components that need to respond
// to the activity lifecycle
}
}
即使這個示例看起來很好,但在真實的應(yīng)用程序中,最終會有太多的調(diào)用來管理UI和其他組件以響應(yīng)生命周期的當(dāng)前狀態(tài)。管理多個組件會在生命周期方法中放置大量代碼,例如onStart()和onStop(),這使得它們難以維護。
此外,無法保證在activity或fragment停止之前啟動組件。尤其是如果我們需要執(zhí)行一個耗時操作,如在onStart()中檢測一些配置。這可能會導(dǎo)致競爭條件,onStop()方法在此之前完成onStart(),使組件保持活動的時間超過其所需的時間。這可能導(dǎo)致競爭的情況,onStop()方法在onStart()之前完成,使組件保持活動的時間超過其所需的時間。
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, location -> {
// update UI
});
}
@Override
public void onStart() {
super.onStart();
Util.checkUserStatus(result -> {
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start();
}
});
}
@Override
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
android.arch.lifecycle提供的類和接口可以幫助您以一種靈活且獨立的方式處理這些問題。
生命周期
Lifecycle是一個類,它保存關(guān)于組件(如activity或fragment)的生命周期狀態(tài)的信息,并允許其他對象觀察該狀態(tài)。
Lifecycle 使用兩個主要枚舉來跟蹤其關(guān)聯(lián)組件的生命周期狀態(tài):
Event
? 從框架和Lifecycle類調(diào)度的生命周期事件 。這些事件映射到活動和片段中的回調(diào)事件。
State
? Lifecycle對象跟蹤的組件的當(dāng)前狀態(tài) 。
[站外圖片上傳中...(image-a27353-1552355707972)]
將狀態(tài)看作圖的節(jié)點,將事件看作這些節(jié)點之間的邊。
類可以通過向其方法添加注釋來監(jiān)視組件的生命周期狀態(tài)。然后,您可以通過調(diào)用Lifecycle類的addObserver() 方法來添加觀察者,并傳遞觀察者的實例,如以下示例所示:
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
...
}
}
myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
在上面的示例中,myLifecycleOwner對象實現(xiàn)了 LifecycleOwner 接口,將在下一節(jié)中進行說明。
LifecycleOwner
LifecycleOwner是僅有一個的方法接口,意味著該類有一個 Lifecycle。它有一個方法getLifecycle(),必須由該類實現(xiàn)。如果您試圖管理整個應(yīng)用程序流程的生命周期,請參閱ProcessLifecycleOwner。
該接口將生命周期的所有權(quán)從各個類(如Fragment和AppCompatActivity)中抽象出來,并允許編寫與其工作的組件。任何自定義應(yīng)用程序類都可以實現(xiàn) LifecycleOwner 接口。
實現(xiàn)LifecycleObserver的組件與實現(xiàn)LifecycleOwner的組件可以無縫地工作,因為所有者可以提供一個生命周期,觀察者可以注冊該生命周期來觀察。
對于位置跟蹤示例,我們可以讓MyLocationListener類實現(xiàn)LifecycleObserver,然后在onCreate()方法中使用activity的Lifecycle初始化它。這使得MyLocationListener類能夠自給自足,這意味著響應(yīng)生命周期狀態(tài)變化的邏輯是在MyLocationListener中聲明的,而不是在activity中。讓各個組件存儲它們自己的邏輯可以使activities和fragments的邏輯更容易管理。
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
// update UI
});
Util.checkUserStatus(result -> {
if (result) {
myLocationListener.enable();
}
});
}
}
一個常見的用例是,如果生命周期目前處于不好的狀態(tài),則避免調(diào)用某些回調(diào)。例如,如果回調(diào)在activity狀態(tài)保存后運行fragment 事務(wù),那么它將觸發(fā)崩潰,因此我們永遠不會調(diào)用該回調(diào)。
為了簡化這個用例, Lifecycle類允許其他對象查詢當(dāng)前狀態(tài)。
class MyLocationListener implements LifecycleObserver {
private boolean enabled = false;
public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {
if (enabled) {
// connect
}
}
public void enable() {
enabled = true;
if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
// connect if not connected
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// disconnect if connected
}
}
通過這種實現(xiàn),我們的LocationListener類完全可以識別生命周期。如果我們需要在另一個activity or fragment中使用LocationListener,我們只需要初始化它。所有設(shè)置和拆卸操作都由類本身管理。
如果庫提供了需要使用Android生命周期的類,我們建議您使用生命周期感知組件。您的庫客戶端可以輕松地集成這些組件,而無需在客戶端進行手動生命周期管理。
實現(xiàn)自定義LifecycleOwner
Support Library 26.1.0 和以后版本中的片段和活動已經(jīng)實現(xiàn)了LifecycleOwner接口。
如果您需要一個自定義類來實現(xiàn)LifecycleOwner,那么您可以使用LifecycleRegistry類,但是您需要將事件轉(zhuǎn)發(fā)到該類中,如下面的代碼示例所示:
public class MyActivity extends Activity implements LifecycleOwner {
private LifecycleRegistry lifecycleRegistry;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
}
@Override
public void onStart() {
super.onStart();
lifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}
生命周期感知組件的最佳實踐
- 保持UI控制器(活動和片段)盡可能精簡。他們不應(yīng)該試圖獲取自己的數(shù)據(jù); 相反,使用
ViewModel來執(zhí)行此操作,并觀察LiveData對象以將更改反映回視圖。 - 嘗試編寫數(shù)據(jù)驅(qū)動的UI,您的UI控制器負責(zé)在數(shù)據(jù)更改時更新視圖,或者將用戶操作通知給
ViewModel。 - 將數(shù)據(jù)邏輯放入
ViewModel類中。ViewModel應(yīng)該作為UI控制器和應(yīng)用程序其余部分之間的連接器。不過要小心,獲取數(shù)據(jù)(例如從網(wǎng)絡(luò))不是ViewModel的職責(zé)。相反,ViewModel應(yīng)該調(diào)用適當(dāng)?shù)慕M件來獲取數(shù)據(jù),然后將結(jié)果返回給UI控制器。 - 使用Data Binding來來維護視圖和UI控制器之間簡潔的接口。這使您可以使視圖更具說明性,并最大限度地減少在
activities和fragments中編寫所需的更新代碼。如果您喜歡在Java編程語言中這樣做,那么可以使用像Butter Knife這樣的庫來避免樣板代碼,并具有更好的抽象。 - 如果UI比較復(fù)雜,可以考慮創(chuàng)建presenter類來處理UI修改。這可能是一個費力的任務(wù),但它可以使您的UI組件更容易測試。
- 避免在你的
ViewModel引用VieworActivitycontext,如果這個ViewModel比Activityd的壽命長(在 configuration changes的情況下),你的activity會泄漏并且不會被垃圾回收器正確的處理
生命周期感知組件的用例
生命周期感知組件可以使您在各種情況下更輕松地管理生命周期。一些例子是:
- 在粗粒度和細粒度位置更新之間切換。使用生命周期感知組件可在您的位置應(yīng)用程序可見時啟用細粒度位置更新,并在應(yīng)用程序位于后臺時切換到粗粒度更新。
LiveData,一個生命周期感知組件,允許您的應(yīng)用在用戶更改位置時自動更新UI。 - 停止和啟動視頻緩沖。使用生命周期感知組件盡快啟動視頻緩沖,但推遲播放直到應(yīng)用程序完全啟動。您還可以使用生命周期感知組件在銷毀應(yīng)用程序時終止緩沖。
- 啟動和停止網(wǎng)絡(luò)連接。使用生命周期感知組件在應(yīng)用程序處于前臺時啟用網(wǎng)絡(luò)數(shù)據(jù)的實時更新(流式傳輸),并在應(yīng)用程序進入后臺時自動暫停。
- 暫停和恢復(fù)動畫繪制。當(dāng)app在后臺時使用生命周期感知組件處理暫停動畫繪制,并在app在前臺后恢復(fù)繪制。
處理停止事件
當(dāng)Lifecycle屬于AppCompatActivity 或Fragment,當(dāng)AppCompatActivity或 Fragment的onSaveInstanceState() 被調(diào)用時,該Lifecycle的狀態(tài)改變?yōu)?a target="_blank" rel="nofollow">CREATED并且ON_STOP 事件被分發(fā)。
當(dāng)Fragment或AppCompatActivity的狀態(tài)通過onSaveInstanceState()保存時,直到調(diào)用ON_START之前,它的UI被認為是不可變的。保存狀態(tài)后試圖修改UI很可能會導(dǎo)致應(yīng)用程序?qū)Ш綘顟B(tài)的不一致,這就是為什么如果應(yīng)用程序在保存狀態(tài)后運行FragmentTransaction,FragmentManager會拋出異常。有關(guān)詳細信息,請參見commit()。
LiveData通過檢測觀察者相關(guān)的生命周期至少在STARTED狀態(tài)才調(diào)用他的觀察者來避免防止這種情況出現(xiàn)。在幕后,它在決定調(diào)用其觀察者之前調(diào)用isAtLeast() 。
不幸的是,AppCompatActivity的onStop()方法是在onSaveInstanceState()之后調(diào)用的,這留下了一個空白,即UI狀態(tài)更改是不允許的,但是Lifecycle還沒有移動到CREATED狀態(tài)。
為了防止出現(xiàn)這個問題,Lifecycle類在beta2和更低的版本在沒有事件調(diào)度的情況下將狀態(tài)標記為CREATED,以便任何檢查當(dāng)前狀態(tài)的代碼都獲得實際值,即使事件未被調(diào)用,直到onStop()才被系統(tǒng)調(diào)用。
不幸的是,這個解決方案有兩個主要問題:
- 在API級別23或更低的級別上,Android系統(tǒng)實際上保存了一個活動的狀態(tài),即使它被另一個活動部分覆蓋。換句話說,Android系統(tǒng)調(diào)用onSaveInstanceState(),但它不一定調(diào)用onStop()。這就產(chǎn)生了一個潛在的長時間間隔,在這個時間間隔中,觀察者仍然認為生命周期是活動的,即使它的UI狀態(tài)不能被修改。
- 任何想要向
LiveData類公開類似行為的類都必須實現(xiàn)Lifecycleversion beta 2或更低版本提供的解決方案。
注意:為了簡化此流并提供與舊版本更好的兼容性,從1.0.0-rc1版本開始,Lifecycle對象被標記為CREATED 并分派ON_STOP事件, 在onSaveInstanceState() 調(diào)用時調(diào)度,而不等待對onStop()方法的調(diào)用。這不太可能影響您的代碼,但您需要注意這一點,因為它與ActivityAPI級別26及更低級別的類中的調(diào)用順序不匹配。
其他資源
要了解有關(guān)使用生命周期感知組件處理生命周期的更多信息,請參閱以下其他資源。
例子
- Android Architecture Components Basic Sample
- Sunflower, 一個演示應(yīng)用程序演示了架構(gòu)組件的最佳實踐