論Android 生命週期感知元件的機制原理
生命週期感知元件執行操作以響應另一個元件(例如 Activity 和 Fragment)的生命週期狀態的更改。這些元件可幫你生成更易於組織、更輕量級、更易於維護的程式碼。
一種常見模式是在 Activity 和 Fragment 的生命週期方法中實現依賴元件的操作。但是這種模式導致程式碼組織混亂和錯誤擴散。通過使用生命週期感知元件,你可以將依賴元件的程式碼移出生命週期方法並移入元件本身。
android.arch.lifecycle
包提供了類和介面,使你可以構建生命週期感知元件 - 這些元件可以根據 Activity 或 Fragment 的當前生命週期狀態自動調整其行為。
Android 框架中定義的大多數應用程式元件都附加了生命週期。生命週期由作業系統或流程中執行的框架程式碼管理。它們是 Android 運作方式的核心,你的應用程式必須尊重它們,不這樣做可能會觸發記憶體洩漏甚至應用程式崩潰。
想象一下,我們有一個 Activity,在螢幕上顯示裝置位置。常見的實現可能如下所示:
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 } }
即使這個示例看起來很好,但在真實的應用程式中,最終會有太多的呼叫來管理 UI 和其他元件以響應生命週期的當前狀態。管理多個元件會在生命週期方法中放置大量程式碼,例如 onStart()
和 onStop()
,這使得它們難以維護。
此外,無法保證元件在 Activity 或 Fragment 停止之前啟動。如果我們需要執行長時間執行的操作,例如 onStart()
中的某些配置檢查,則尤其如此。這可能會導致 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
Lifecycle
是一個類,它包含有關元件生命週期狀態的資訊(如 Activity 或 Fragment),並允許其他物件觀察此狀態。
Lifecycle
使用兩個主要列舉來跟蹤其關聯元件的生命週期狀態:
Event
從框架和 Lifecycle
類排程的生命週期事件。這些事件對映到 Activity 和 Fragment 中的回撥事件。
State
Lifecycle
物件跟蹤的元件的當前狀態。

將狀態視為圖形的節點,將事件視為這些節點之間的邊緣。
類可以通過向其方法添加註釋來監視元件的生命週期狀態。然後,可以通過呼叫 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
物件實現了 LifecycleOwner
介面,將在下一節中進行說明。
LifecycleOwner
LifecycleOwner
是一個單一方法介面,表示該類具有生命週期。它有一個方法 getLifecycle()
,必須由類實現。如果您正嘗試管理整個應用程式程序的生命週期,請參閱 ProcessLifecycleOwner
。
此介面從各個類(如 Fragment
和 AppCompatActivity
)中抽象出生命週期的所有權,並允許編寫與其一起使用的元件。任何自定義應用程式類都可以實現 LifecycleOwner
介面。
實現 LifecycleObserver
的元件與實現 LifecycleOwner
的元件無縫協作,因為所有者可以提供生命週期,觀察者可以註冊觀察。
對於位置跟蹤示例,我們可以使 MyLocationListener
類實現 LifecycleObserver
,然後在 onCreate()
方法中使用 Activity 的 Lifecycle
初始化它。這允許 MyLocationListener
類自給自足,這意味著響應生命週期狀態變化的邏輯在 MyLocationListener
而不是 Activity 中宣告。使各個元件儲存自己的邏輯使得 Activity 和 Fragment 邏輯更易於管理。
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(); } }); } }
一個常見的用例是,如果生命週期現在不處於良好狀態,則應避免呼叫某些回撥。例如,如果回撥在儲存 Activity 狀態後執行 Fragment 事務,則會觸發崩潰,因此我們永遠不會想要呼叫該回調。
為了簡化此用例, Lifecycle
類允許其他物件查詢當前狀態。
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 } }
通過此實現,我們的 LocationListener
類完全可以識別生命週期。如果我們需要使用來自另一個 Activity 或 Fragment 的 LocationListener
,我們只需要初始化它。所有設定和拆卸操作都由類本身管理。
如果庫提供了需要使用 Android 生命週期的類,我們建議你使用生命週期感知元件。你的庫客戶端可以輕鬆地整合這些元件,而無需在客戶端進行手動生命週期管理。
實現自定義 LifecycleOwner
支援庫 26.1.0 及更高版本中的 Fragment 和 Activity 已實現 LifecycleOwner
介面。
如果您有一個想要建立 LifecycleOwner
的自定義類,則可以使用 LifecycleRegistry
類,但需要將事件轉發到該類中,如以下程式碼示例所示:
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 控制器(Activity 和 Fragment)儘可能精簡。他們不應該試圖獲取自己的資料;相反,使用
ViewModel
執行此操作,並觀察LiveData
物件以將更改反映回檢視。 - 嘗試編寫資料驅動的 UI,其中 UI 控制器負責在資料更改時更新檢視,或將使用者操作通知給
ViewModel
。 - 將您的資料邏輯放在
ViewModel
類中。ViewModel
應該充當 UI 控制器和應用程式其餘部分之間的聯結器。但要小心,ViewModel
不負責獲取資料(例如從網路獲取)。相反,ViewModel
應呼叫適當的元件來獲取資料,然後將結果返回 UI 控制器。 - 使用資料繫結來維護檢視和 UI 控制器之間的乾淨介面。這使您可以使檢視更具說明性,並最大限度地減少在 Activity 和 Fragment 中編寫所需的更新程式碼。如果您更喜歡用 Java 程式語言執行此操作,請使用像
Butter Knife
這樣的庫來避免樣板程式碼並具有更好的抽象。 - 如果您的 UI 很複雜,請考慮建立一個
presenter
類來處理 UI 修改。這可能是一項艱鉅的任務,但它可以使您的 UI 元件更容易測試。 - 避免在
ViewModel
中引用View
或Activity
上下文。如果ViewModel
超過 Activity(在配置更改的情況下)生存時間,將導致 Activity 記憶體洩漏,並且垃圾收集器未正確處理。
生命週期感知元件的用例
生命週期感知元件可以使你在各種情況下更輕鬆地管理生命週期。一些例子是:
LiveData
處理停止事件
當生命週期屬於 AppCompatActivity
或 Fragment
時, Lifecycle
的狀態將更改為 CREATED
,並且在呼叫 AppCompatActivity
或 Fragment
的 onSaveInstanceState()
時排程 ON_STOP
事件。
當通過 onSaveInstanceState()
儲存 Fragment
或 AppCompatActivity
的狀態時,在呼叫 ON_START
之前,它的UI被認為是不可變的。儲存狀態後嘗試修改UI可能會導致應用程式的導航狀態不一致,這就是如果應用程式在儲存狀態後執行 FragmentTransaction
時, FragmentManager
會丟擲異常的原因。有關詳細資訊,請參閱 commit()
。
如果觀察者的關聯生命週期至少沒有開始, LiveData
會通過禁止呼叫其觀察者來防止這種邊緣情況開箱即用。在幕後,它在決定呼叫其觀察者之前呼叫 isAtLeast()
。
不幸的是,在 onSaveInstanceState()
之後呼叫 AppCompatActivity的onStop()
方法,這留下了一個間隙,其中不允許UI狀態更改但 Lifecycle
尚未移至 CREATED
狀態。
為防止出現此問題,版本 beta2 及更低版本的 Lifecycle
類將狀態標記為 CREATED
,而不排程事件,以便檢查當前狀態的任何程式碼都獲得實際值,即使事件未排程,直到系統呼叫 onStop()
。
不幸的是,這個解決方案有兩個主要問題:
- 在 API 級別 23 和更低級別,Android 系統實際上儲存了 Activity 的狀態,即使它被另一個 Activity 部分覆蓋。換句話說,Android 系統呼叫
onSaveInstanceState()
但它不一定呼叫onStop()
。這會建立一個可能很長的時間間隔,即使無法修改其 UI 狀態,觀察者仍然認為生命週期處於活動狀態。 - 任何想要向
LiveData
類公開類似行為的類都必須實現Lifecycle
version beta 2 及更低版本提供的解決方法。
私以為,lifecycle 的目的就是解除業務邏輯和 UI 控制器的耦合,使 UI 控制器保持單一職責,這樣程式碼也更容易組織和維護。配合 LiveData
和 ViewModel
來實現 Clean Architecture,這也是 Android 官方推薦的做法。
最後
在現在這個金三銀四的面試季,我自己在網上也蒐集了很多資料做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】:加入群聊

資料大全