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