摘要:生命周期感知組件會執行操作來響應另一個組件如和的生命周期狀態的改變。使用兩個主要枚舉來追蹤其關聯組件的生命周期狀態從和類中分發的生命周期事件,這些事件映射到和的回調事件中。
生命周期感知組件會執行操作來響應另一個組件(如 activity 和 fragment)的生命周期狀態的改變。這些組件可以幫助你生成組織性更好、更輕量級、更易于維護的代碼。
一個常見的模式是在 activity 和 fragment 的生命周期方法中實現依賴組件的動作。但是,這種模式會導致代碼的組織不良以及錯誤的擴散。通過使用生命周期感知組件,可以將依賴組件的代碼從生命周期方法中轉移到組件本身。
android.arch.lifecycle 包提供了一些類和接口,讓你可以構建生命周期感知組件,這些組件可以根據活動或片段的當前生命周期狀態自動調整自己的行為。
注意:要將?android.arch.lifecycle?包導入到你的 Android 項目中, 請參閱?adding components to your project。
Android Framework 中定義的大多數應用程序組件都附帶有生命周期。生命周期由操作系統或在你的進程中運行的框架代碼進行管理。它們是 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 包提供的類和接口可以幫助你以彈性和獨立的方式解決這些問題。
LifecycleLifecycle 是一個類,它保存組件(如 activity 或 fragment)的生命周期狀態信息,并允許其他對象觀察此狀態。
Lifecycle 使用兩個主要枚舉來追蹤其關聯組件的生命周期狀態:
Event
?從 framework 和 Lifecycle 類中分發的生命周期事件,這些事件映射到 activity 和 fragment 的回調事件中。
State
?Lifecycle 對象追蹤的組件的當前狀態。
把 states 看作圖形的節點,events 看作這些節點的邊。
一個類可以通過給它的方法添加注解來監聽組件的生命周期,然后,你可以通過調用 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 接口,下一節會對其進行解釋。
LifecycleOwnerLifecycleOwner是一個表示該類有一個 Lifecycle 的單方法接口。它有一個必須被該類實現的 getLifecycle() 方法。如果你試圖去管理整個應用程序進程的生命周期,請參閱 ProcessLifecycleOwner。
這個接口從各個類(如 Fragment 和 AppCompatActivity)提取 Lifecycle 的所有權,并允許編寫與它們一起工作的組件。任何自定義的應用程序類都可以實現 LifecycleOwner 接口。
實現 LifecycleObserver 的組件與實現 LifecycleOwner的組件無縫協作,因為 owner 可以提供 observer 可以注冊的生命周期。
對位置追蹤示例來說,我們可以讓 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(); } }); } }
一個常見的用例是,如果現在 Lifecycle 不在一個好的狀態,那么避免調用某些 callback。例如,如果 callback 在 activity 狀態被保存之后執行一個 fragment 事務,會觸發崩潰,所以我們絕對不會調用該 callback。
為了簡化這個用例,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 生命周期工作的類,我們建議你使用生命周期感知組件。庫客戶端可以輕松地集成這些組件,而無須在客戶端進行手動生命周期管理。
實現一個自定義的 LifecycleOwner26.1.0 及更高版本的 Support Library 中的 Fragments and Activities 已經實現了 LifecycleOwner 接口。
如果你有一個想要作為 LifecycleOwner 的自定義類,你可以使用 LifecycleRegistry 類,但是你需要將事件轉發到該類中,如下代碼所示:
public class MyActivity extends Activity implements LifecycleOwner { private LifecycleRegistry mLifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mLifecycleRegistry = new LifecycleRegistry(this); mLifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public void onStart() { super.onStart(); mLifecycleRegistry.markState(Lifecycle.State.STARTED); } @NonNull @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; } }生命周期感知組件的最佳實踐
保持 UI 控制器盡可能精簡,它們不應該試圖獲取自己的數據,作為替代,使用 ViewModel 來做到這一點,并觀察一個 LiveData 對象,將變化反映給視圖。
嘗試編寫數據驅動的 UI,該 UI 的 UI 控制器的職責是在數據變化時更新視圖,或者將用戶操作通知給ViewModel。
把數據邏輯放在 ViewModel 類中, ViewModel 應該充當 UI 控制器和應用程序其他部分的連接器。但是要小心,獲取數據(例如從網絡)并不是 ViewModel 的職責,作為替代, ViewModel 應該調用適當的組件來獲取數據,然后將結果提供給 UI 控制器。
使用 Data Binding 在視圖和 UI 控制器之間維護一個清爽的接口。這允許你讓視圖更具聲明性,并最大限度的減少需要在 activities 和 fragments 中寫入的更新代碼。如果你更喜歡用 Java 編程語言來實現這一點,請使用類似 Butter Knife 的庫來避免樣板代碼,并具有更好的抽象。
如果你的 UI 很復雜,請考慮創建一個 presenter 類來處理 UI 修改。這可能是一項艱巨的任務,但它可以使 UI 組件更易于測試。
避免在 ViewModel 中引用View 或 Activity 上下文。如果 ViewModel 存活時間比 activity 更長(在配置更改的情況下),那么 activity 會泄露,并且無法被 GC 正確處理。
生命周期感知組件的用例生命周期感知組件可以使你在各種情況下更容易管理生命周期。這里是一些例子:
在粗略和精細的位置信息更新之前切換。使用生命周期感知組件,在 location app 可見時啟用精細的位置更新,當應用處于后臺時切換到粗略的位置更新。LiveData 是一種生命周期感知組件,它允許應用程序在位置改變時自動更新 UI。
停止和啟動視頻緩沖。使用生命周期感知組件盡快啟動視頻緩沖,但是將播放推遲到應用完全啟動的時候。你也可以使用生命周期感知組件在應用銷毀時終止緩沖。
啟動和停止網絡連接。使用生命周期感知組件,在應用處于前臺時啟動網絡數據傳輸,在應用進入后臺時自動暫停。
暫停和恢復動畫繪制。使用生命周期感知組件,在應用處于后臺時暫停動畫繪制,當應用處于前臺時恢復繪制。
處理停止事件當 Lifecycle 屬于AppCompatActivity 或 Fragment ,在 AppCompatActivity 或 Fragment 的 onSaveInstanceState() 被調用時,Lifecycle 的狀態改變為CREATED,ON_STOP 事件被分發。
當 Fragment 或 AppCompatActivity 的狀態通過 onSaveInstanceState() 保存時,直到 ON_START 被調用為止,它的 UI 被認為是不可變的。嘗試在保存狀態后修改 UI,可能會導致應用的導航狀態不一致,這就是如果應用程序在保存狀態后運行 FragmentManager,FragmentManager 拋出異常的原因,詳情請參閱 commit()。
如果 observer 關聯的 Lifecycle 的狀態至少不是 STARTED,LiveData 可以通過避免調用它的 observer 來防止這種極端情況的出現。在幕后,它在決定調用 observer 之前調用了 isAtLeast()。
不幸的是,AppCompatActivity 的 onStop() 方法是在 onSaveInstanceState() 之后被調用的,這會在 UI 狀態更改不被允許但 Lifecycle 還沒有移至 CREATED 狀態情況下留下空隙。
為了避免這個問題,beta2 和更低版本的 Lifecycle 類,將狀態標記為 CREATED,而不分發事件,這樣任何檢查當前狀態的代碼都會得到真實值,即使事件直到 onStop() 被系統調用才會被分發。
不幸的是,這個解決方案有兩個主要問題:
在 API 23及更低版本上,Android 系統實際上保存了 activity 的狀態,即使它被另一個 activity 部分覆蓋。換句話說,Android 系統調用 onSaveInstanceState(),但不一定調用 onStop()。這會產生一個潛在的長時間間隔,即使其 UI 狀態不能被修改,觀察者仍認為生命周期是活動的。
任何想要暴露類似行為給 LiveData 類的類必須實現 beta 2以下版本 Lifecycle 提供的變通方法。
注意:為了使這個流程更簡單,并提供與舊版本更好的兼容性,從 1.0.0-rc1 開始,Lifecycle 對象被標記為CREATED ,并且在 onSaveInstanceState() 被調用時分發 ON_STOP,而不等待 onStop() 方法的調用。這不太可能影響你的代碼,但你需要注意的是,這與 API 26 以下的 Activity 中的調用順序不匹配。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70824.html
閱讀 1975·2023-04-26 01:59
閱讀 3278·2021-10-11 11:07
閱讀 3309·2021-09-22 15:43
閱讀 3390·2021-09-02 15:21
閱讀 2573·2021-09-01 10:49
閱讀 913·2019-08-29 15:15
閱讀 3101·2019-08-29 13:59
閱讀 2841·2019-08-26 13:36