官方文檔鏈接:https://developer.android.google.cn/topic/libraries/architecture/lifecycle.html
1.前言
上一篇文章大體介紹了框架的層級(jí)和優(yōu)勢,接下來的幾篇將詳細(xì)介紹各個(gè)特性祸憋。首先來了解一下組件生命周期的管理杆查,以及如何將業(yè)務(wù)與生命周期相關(guān)聯(lián)蚀腿。
2.使用案例
android.arch.lifecycle
包提供了類和接口,以便實(shí)現(xiàn)生命周期感知組件,能自動(dòng)根據(jù)當(dāng)前Activity和Fragment的狀態(tài)調(diào)整行為。
假設(shè)一個(gè)場景邪财,通過一個(gè)Activity在屏幕上顯示設(shè)備當(dāng)前的位置。下面是最常見的寫法:
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;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, (location) -> {
// update UI
});
}
public void onStart() {
super.onStart();
myLocationListener.start();
}
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
雖然這個(gè)例子看起來不錯(cuò)质欲,但在實(shí)際項(xiàng)目中树埠,會(huì)有大量的類似需求,導(dǎo)致onStart()
和onStop()
方法變得很臃腫嘶伟。此外怎憋,有些組件無法直接在onStart()
方法中啟動(dòng),比如在啟動(dòng)定位服務(wù)前需檢查一些配置九昧。某些情況下绊袋,Activity已經(jīng)停止了,檢查才結(jié)束铸鹰,意味著 myLocationListener.stop()
調(diào)用之后才調(diào)用myLocationListener.start()
方法癌别。
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, location -> {
// update UI
});
}
public void onStart() {
super.onStart();
Util.checkUserStatus(result -> {
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start();
}
});
}
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
3.Lifecycle類
Lifecycle是一個(gè)類,持有組件(Activity和Fragment)生命周期狀態(tài)的信息蹋笼,并允許其它對(duì)象觀察狀態(tài)展姐。主要由以下兩個(gè)部分組成:
- Event:這些事件與Activity和Fragment的系統(tǒng)回調(diào)一一對(duì)應(yīng)。
- State:組件的當(dāng)前狀態(tài)由Lifecycle對(duì)象管理姓建。
State是圖形中的一個(gè)個(gè)節(jié)點(diǎn)诞仓,而Event則是節(jié)點(diǎn)之間的線。點(diǎn)可以存在很長或很短時(shí)間速兔,線象征著變化的過程。通過給一個(gè)類的方法添加注釋來管理相應(yīng)組件的生命周期狀態(tài)活玲。
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
}
}
aLifecycleOwner.getLifecycle().addObserver(new MyObserver());
4.LifecycleOwner類
LifecycleOwner是擁有單一方法getLifecycle()
的接口涣狗,表示實(shí)現(xiàn)類有一個(gè)Lifecycle谍婉。通過它獲取到組件(Activity,F(xiàn)ragment)的Lifecycle镀钓,從而能讓其它的組件一起工作穗熬。自定義的Application可以實(shí)現(xiàn)此接口以提供生命周期。
由于架構(gòu)組件還處于alpha階段丁溅,不能將不穩(wěn)定的API引入到穩(wěn)定的代碼中唤蔗,所以Fragment和AppCompatActivity類未能實(shí)現(xiàn)此接口。在Lifecycle穩(wěn)定前窟赏,可以使用LifecycleActivity和LifecycleFragment代替妓柜。等正式版發(fā)布后,支持庫中的Activity和Fragment將會(huì)實(shí)現(xiàn)LifecycleOwner接口涯穷,而LifecycleActivity和LifecycleFragment也將同時(shí)廢棄棍掐。
上面的例子,可以讓MyLocationListener類實(shí)現(xiàn)LifecycleObserver接口拷况,并在組件onCreate()
方法中通過Lifecycle初始化作煌。這樣它就能自己管理,必要時(shí)還能清理自己赚瘦。
class MyActivity extends LifecycleActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
// update UI
});
Util.checkUserStatus(result -> {
if (result) {
myLocationListener.enable();
}
});
}
}
當(dāng)Lifecycle不在一個(gè)好的狀態(tài)時(shí)粟誓,有些回調(diào)通常是不能調(diào)用的。例如起意,當(dāng)Activity的狀態(tài)是銷毀的努酸,若在回調(diào)中執(zhí)行Fragment事務(wù),將會(huì)導(dǎo)致crash杜恰,所以此時(shí)不希望啟用回調(diào)获诈。
為了讓實(shí)例簡單,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.getState().isAtLeast(STARTED)) {
// connect if not connected
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// disconnect if connected
}
}
這樣實(shí)現(xiàn)后舔涎,MyLocationListener類已可以感知生命周期了,不需要在Activity中管理初始化和釋放了逗爹。如果另一個(gè)Activity或Fragment需要使用此類亡嫌,僅僅需要初始化它,所有的安裝和拆卸操作由它自己管理掘而。
LiveData就是生命周期感知組件挟冠,與ViewModel一起使用,可以在遵守生命周期下更容易地為界面提供數(shù)據(jù)袍睡。
5.最佳實(shí)踐
- 保持UI Controller(Activity和Fragment)代碼盡可能少知染。它們不應(yīng)該自己存儲(chǔ)數(shù)據(jù);相反斑胜,應(yīng)由ViewModel提供控淡,并觀察LiveData以便將變化反映到視圖上嫌吠。
- 嘗試數(shù)據(jù)驅(qū)動(dòng)界面,UI Controller負(fù)責(zé)數(shù)據(jù)變化時(shí)更新界面掺炭,或者將用戶操作反饋給ViewModel辫诅。
- ViewModel類中放入數(shù)據(jù)邏輯,作為UI Controller和應(yīng)用其它部分的連接涧狮。不過需注意炕矮,獲取數(shù)據(jù)不是它的職責(zé)(例如,網(wǎng)絡(luò)請求)者冤;相反肤视,應(yīng)該調(diào)用相關(guān)組件來做,再將結(jié)果返回給UI Controller譬嚣。
- 使用Data Binding在View和UI Controller之間保持干凈的接口钢颂。這將使View的功能清楚且省去Activity和Fragment中更新界面的代碼。如果喜歡在代碼中完成拜银,可以使用Butter Knife庫來避免樣板代碼和獲得更好的抽象殊鞭。
- 如果界面過于復(fù)雜,可創(chuàng)建Presenter類處理界面的修改行為尼桶。通常沒必要操灿,但是可以使界面更容易測試。
- 不要在ViewModel中引用View或Activity的上下文泵督。因?yàn)樗纳芷谳^長(比如配置改變時(shí))趾盐,導(dǎo)致View或Activity泄露,無法被垃圾回收小腊。
6.自定義實(shí)現(xiàn)LifecycleOwner
支持庫版本26.1.0之后救鲤,Activity和Fragment已經(jīng)實(shí)現(xiàn)LifecycleOwner。如果自定義一個(gè)類實(shí)現(xiàn)LifecycleOwner秩冈,需要讓它持有LifecycleRegistry對(duì)象本缠,并調(diào)用handleLifecycleEvent(Lifecycle.Event event)
方法分發(fā)事件。
LifecycleRegistry的使用入问,可以參考別人翻譯的老版文檔丹锹,如下:
public class MyFragment extends Fragment implements LifecycleRegistryOwner {
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}
7.總結(jié)
將業(yè)務(wù)行為放到Activity和Fragment等組件中,無非就是方便獲取界面交互事件和生命周期芬失。MVP架構(gòu)中將業(yè)務(wù)行為放到Presenter中楣黍,通過View層去調(diào)用,而現(xiàn)在創(chuàng)建多個(gè)類來監(jiān)聽生命周期棱烂,并在其中實(shí)現(xiàn)各自業(yè)務(wù)的邏輯租漂,使結(jié)構(gòu)更加清晰,避免Presenter過于龐大。