有了整體的認(rèn)識(shí)缸废,就可以對(duì)之前沒有詳細(xì)介紹的類做一個(gè)深入的探究仅仆。首先來看看Lifecycle。
Handling Lifecycles
android.arch.lifecycle提供的類和接口可以讓你構(gòu)建能感知生命周期(lifecycle-aware)的類兜畸。所謂可以感知生命周期就是能夠根據(jù)Activity或者Fragment的生命周期自行調(diào)整類的行為梧油。
Android系統(tǒng)中定義的大多數(shù)組件都是有生命周期的。這些組件的生命周期是由系統(tǒng)管理的夹姥。作為一個(gè)開發(fā)者必須遵守這些生命周期的規(guī)則杉武,否則就會(huì)出現(xiàn)內(nèi)存泄漏或者應(yīng)用崩潰的情況。
這么說好像有點(diǎn)無力啊辙售,讓我們一起舉個(gè)例子吧轻抱。比如我們需要在Activity中做一個(gè)對(duì)位置的監(jiā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;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, (location) -> {
// update UI
});
}
public void onStart() {
super.onStart();
myLocationListener.start();
}
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
在Activity的onCreate()方法中創(chuàng)建Listener
,在onStart()
時(shí)開始監(jiān)聽旦部,在onStop()
中停止監(jiān)聽祈搜。看起來一切正常啊士八,就是可能Activty不停的切換會(huì)調(diào)用多次LocationListener的onStart
和onStop
而已容燕。
但是問題來了,舉個(gè)例子哈婚度。比如有些App會(huì)提供一個(gè)選項(xiàng)缰趋,說允不允許提供位置,那么在定位之前就需要檢查這些設(shè)置陕见。好,那么就在Activity里提供檢查的代碼:
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();
}
}
看起來好像也沒有問題呀秘血,讓我們來一起分析一下這段代碼。假如程序執(zhí)行到super.onStart()
這里還沒等checkUserStatus執(zhí)行完成就執(zhí)行了onStop()
(這里就假設(shè)檢查本身回花費(fèi)時(shí)間比較長吧)评甜,意識(shí)到出了什么問題了嗎灰粮?myLocationListener
的stop()
方法在start()
之前執(zhí)行了,這本身在邏輯上就是不合理的忍坷。更嚴(yán)重的問題是:myLocationListener
過一段時(shí)間開始執(zhí)行start()
粘舟,然后沒有stop的代碼被調(diào)用了。這意味著如果沒有其他操作佩研,Activity將會(huì)一直在后臺(tái)監(jiān)聽Location的改變柑肴。
Lifecycle就是用來解決這些問題的,并且解決的非常優(yōu)雅(in a resilient and isolated way)旬薯。
Lifecycle
Lifecycle是一個(gè)包含組件(Activity或者Fragment)生命周期狀態(tài)的類晰骑,這個(gè)類還能夠?yàn)槠渌愄峁┊?dāng)前的生命周期。
Lifecycle使用兩個(gè)主要的枚舉來跟蹤他所關(guān)聯(lián)組件的生命周期绊序。
- Event 事件 從組件或者Lifecycle類分發(fā)出來的生命周期硕舆,它們和Activity/Fragment生命周期的事件一一對(duì)應(yīng)秽荞。(ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY)
- State 狀態(tài) 當(dāng)前組件的生命周期狀態(tài)(INITIALIZED,DESTROYED,CREATED,STARTED,RESUMED)
說的有點(diǎn)抽象了,看一下下面的圖:
具體的代碼如下:
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
}
}
//aLifecycleOwner一般是實(shí)現(xiàn)了LifecycleOwner的類抚官,比如Activity/Fragment
aLifecycleOwner.getLifecycle().addObserver(new MyObserver());
LifecycleOwner
那什么是LifecycleOwner呢扬跋?實(shí)現(xiàn)LifecycleOwner就表示這是個(gè)有生命周期的類,他有一個(gè)getLifecycle ()方法是必須實(shí)現(xiàn)的凌节。com.android.support:appcompat-v7:26.1.0
中的AppCompatActivity已經(jīng)實(shí)現(xiàn)了這個(gè)接口钦听,詳細(xì)的實(shí)現(xiàn)可以自行查看代碼。
對(duì)于前面提到的監(jiān)聽位置的例子倍奢∑由希可以把MyLocationListener
實(shí)現(xiàn)LifecycleObserver,然后在Lifecycle
(Activity/Fragment)的onCreate
方法中初始化。這樣MyLocationListener
就能自行處理生命周期帶來的問題娱挨。具體代碼如下:
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();
}
});
}
}
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
}
}
簡單過一下上面的代碼不難發(fā)現(xiàn)這樣可以解決文章開始提到的問題余指。(調(diào)用enable()時(shí)捕犬,已經(jīng)處于CREATED狀態(tài)跷坝,下面的代碼是不會(huì)執(zhí)行的)這樣在如果Lifecycle沒有處在合適的時(shí)機(jī)是不會(huì)調(diào)用相關(guān)回調(diào)的。現(xiàn)在MyLocationListener
是有生命周期感知能力的(lifecycle-aware),不再依賴Activity的生命周期碉碉。
Lifecycles的最佳建議
- 保持UI Controllers(Activity/Fragment)中代碼足夠簡潔柴钻。一定不能包含如何獲取數(shù)據(jù)的代碼,要通過ViewModel獲取LiveData形式的數(shù)據(jù)垢粮。
- 用數(shù)據(jù)驅(qū)動(dòng)UI贴届,UI的職責(zé)就是根據(jù)數(shù)據(jù)改變顯示的內(nèi)容,并且把用戶操作UI的行為傳遞給ViewModel蜡吧。
- 把業(yè)務(wù)邏輯相關(guān)的代碼放到ViewModel中毫蚓,把ViewModel看成是鏈接UI和App其他部分的膠水。但ViewModel不能直接獲取數(shù)據(jù)昔善,要通過調(diào)用其他類來獲取數(shù)據(jù)元潘。
- 使用DataBinding來簡化View(布局文件)和UI Controllers(Activity/Fragment)之間的代碼
- 如果布局本身太過復(fù)雜,可以考慮創(chuàng)建一個(gè)Presenter類來處理UI相關(guān)的改變君仆。雖然這么做會(huì)多寫很多代碼翩概,但是對(duì)于保持UI的簡介和可測試性是有幫助的。
- 不要在ViewModel中持有任何View/Activity的context返咱。否則會(huì)造成內(nèi)存泄露钥庇。
附加說明
在 Support Library 26.1.0中Activity/Fragment已經(jīng)實(shí)現(xiàn)了LifecycleOwner接口。
如果想在自定義的類中實(shí)現(xiàn)LifecyclerOwner咖摹,就需要用到LifecycleRegistry,并且需要自行發(fā)送Event评姨。
相關(guān)文章:
理解Android Architecture Components系列(一)
理解Android Architecture Components系列(二)
理解Android Architecture Components系列之Lifecycle(三)
理解Android Architecture Components系列之LiveData(四)
理解Android Architecture Components系列之ViewModel(五)
理解Android Architecture Components系列之Room(六)
理解Android Architecture Components系列之Paging Library(七)
理解Android Architecture Components系列之WorkManager(八)