爭取打造 Android Jetpack 講解的最好的部落格系列:
Android Jetpack 實戰篇:
概述
在過去的谷歌IO大會上,Google官方向我們推出了 Android Architecture Components,其中談到Android元件處理生命週期的問題,向我們介紹了 Handling Lifecycles。
同時,如何利用 android.arch.lifecycle
包提供的類來控制資料、監聽器等的 lifecycle。同時,LiveData 與 ViewModel 的 lifecycle 也依賴於 Lifecycle 框架。
一、Lifecycle簡介&基礎使用
為什麼要引進Lifecycle?
我們在處理Activity或者Fragment元件的生命週期相關時,不可避免會遇到這樣的問題:
我們在Activity的onCreate()中初始化某些成員(比如MVP架構中的Presenter,或者AudioManager、MediaPlayer等),然後在onStop中對這些成員進行對應處理,在onDestroy中釋放這些資源,這樣導致我們的程式碼也許會像這樣:
class MyPresenter{
public MyPresenter() {
}
void create() {
//do something
}
void destroy() {
//do something
}
}
class MyActivity extends AppCompatActivity {
private MyPresenter presenter;
public void onCreate(...) {
presenter= new MyPresenter ();
presenter.create();
}
public void onDestroy() {
super.onDestroy();
presenter.destory();
}
}
複製程式碼
程式碼沒有問題,關鍵問題是,實際生產環境中 ,這樣的程式碼會非常複雜,你最終會有太多的類似呼叫並且會導致 onCreate() 和 onDestroy() 方法變的非常臃腫。
解決方案
Lifecycle 是一個類,它持有關於元件(如 Activity 或 Fragment)生命週期狀態的資訊,並且允許其他物件觀察此狀態。
我們只需要2步:
1、Prestener繼承LifecycleObserver介面
public interface IPresenter extends LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(@NotNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(@NotNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onLifecycleChanged(@NotNull LifecycleOwner owner,
@NotNull Lifecycle.Event event);
}
public class BasePresenter implements IPresenter {
private static final String TAG = "com.qingmei2.module.base.BasePresenter";
@Override
public void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event) {
}
@Override
public void onCreate(@NotNull LifecycleOwner owner) {
Log.d("tag", "BasePresenter.onCreate" + this.getClass().toString());
}
@Override
public void onDestroy(@NotNull LifecycleOwner owner) {
Log.d("tag", "BasePresenter.onDestroy" + this.getClass().toString());
}
}
複製程式碼
這裡我直接將我想要觀察到Presenter的生命週期事件都列了出來,然後封裝到BasePresenter 中,這樣每一個BasePresenter 的子類都能感知到Activity容器對應的生命週期事件,並在子類重寫的方法中,對應相應行為。
2、在Activity/Fragment容器中新增Observer:
public class MainActivity extends AppCompatActivity {
private IPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("tag", "onCreate" + this.getClass().toString());
setContentView(R.layout.activity_main);
mPresenter = new MainPresenter(this);
getLifecycle().addObserver(mPresenter);//新增LifecycleObserver
}
@Override
protected void onDestroy() {
Log.d("tag", "onDestroy" + this.getClass().toString());
super.onDestroy();
}
}
複製程式碼
如此,每當Activity發生了對應的生命週期改變,Presenter就會執行對應事件註解的方法:
除onCreate和onDestroy事件之外,Lifecycle一共提供了所有的生命週期事件,只要 通過註解進行宣告,就能夠使LifecycleObserver觀察到對應的生命週期事件:
//以下為logcat日誌
01-08 23:21:01.702 D/tag: onCreate class com.qingmei2.mvparchitecture.mvp.ui.MainActivity
01-08 23:21:01.778 D/tag: onCreate class com.qingmei2.mvparchitecture.mvp.presenter.MainPresenter
01-08 23:21:21.074 D/tag: onDestroy class com.qingmei2.mvparchitecture.mvp.presenter.MainPresenter
01-08 23:21:21.074 D/tag: onDestroy class com.qingmei2.mvparchitecture.mvp.ui.MainActivity
複製程式碼
public enum Event {
/**
* Constant for onCreate event of the {@link LifecycleOwner}.
*/
ON_CREATE,
/**
* Constant for onStart event of the {@link LifecycleOwner}.
*/
ON_START,
/**
* Constant for onResume event of the {@link LifecycleOwner}.
*/
ON_RESUME,
/**
* Constant for onPause event of the {@link LifecycleOwner}.
*/
ON_PAUSE,
/**
* Constant for onStop event of the {@link LifecycleOwner}.
*/
ON_STOP,
/**
* Constant for onDestroy event of the {@link LifecycleOwner}.
*/
ON_DESTROY,
/**
* An {@link Event Event} constant that can be used to match all events.
*/
ON_ANY
}
複製程式碼
二、原理分析
先說結論:
借鑑Android 架構元件(一)——Lifecycle, @ShymanZhu的一張圖進行簡單的概括:
我們先將重要的這些類挑選出來:
-
LifecycleObserver介面( Lifecycle觀察者):實現該介面的類,通過註解的方式,可以通過被LifecycleOwner類的addObserver(LifecycleObserver o)方法註冊,被註冊後,LifecycleObserver便可以觀察到LifecycleOwner的生命週期事件。
-
LifecycleOwner介面(Lifecycle持有者):實現該介面的類持有生命週期(Lifecycle物件),該介面的生命週期(Lifecycle物件)的改變會被其註冊的觀察者LifecycleObserver觀察到並觸發其對應的事件。
-
Lifecycle(生命週期):和LifecycleOwner不同的是,LifecycleOwner本身持有Lifecycle物件,LifecycleOwner通過其Lifecycle getLifecycle()的介面獲取內部Lifecycle物件。
-
State(當前生命週期所處狀態):如圖所示。
-
Event(當前生命週期改變對應的事件):如圖所示,當Lifecycle發生改變,如進入onCreate,會自動發出ON_CREATE事件。
瞭解了這些類和介面的職責,接下來原理分析就簡單很多了,我們以Fragment為例,來看下實際Fragment等類和上述類或介面的聯絡:
1、Fragment:LifecycleOwner
- Fragment(Activity同理,我們 本文以Fragment為例,下同):實現了LifecycleOwner介面,這意味著Fragment物件持有生命週期物件(Lifecycle),並可以通過Lifecycle getLifecycle()方法獲取內部的Lifecycle物件:
public class Fragment implements xxx, LifecycleOwner {
//...省略其他
LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
複製程式碼
可以看到,實現的getLifecycle()方法,實際上返回的是 LifecycleRegistry 物件,LifecycleRegistry物件實際上繼承了 Lifecycle,這個下文再講。
持有Lifecycle有什麼作用呢?實際上在Fragment對應的生命週期內,都會傳送對應的生命週期事件給內部的 LifecycleRegistry物件處理:
public class Fragment implements xxx, LifecycleOwner {
//...
void performCreate(Bundle savedInstanceState) {
onCreate(savedInstanceState); //1.先執行生命週期方法
//...省略程式碼
//2.生命週期事件分發
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
void performStart() {
onStart();
//...
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
}
void performResume() {
onResume();
//...
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
void performPause() {
//3.注意,呼叫順序變了
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
//...
onPause();
}
void performStop() {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
//...
onStop();
}
void performDestroy() {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
//...
onDestroy();
}
}
複製程式碼
隨著Fragment不同走到不同的生命週期,除了暴露給我們的生命週期方法onCreate/onStart/..../onDestroy等,同時,Fragment內部的Lifecycle物件(就是mLifecycleRegistry)還將生命週期對應的事件作為引數傳給了 handleLifecycleEvent() 方法。
同時,你會發現Fragment中performCreate()、performStart()、performResume()會先呼叫自身的onXXX()方法,然後再呼叫LifecycleRegistry的handleLifecycleEvent()方法;而在performPause()、performStop()、performDestroy()中會先LifecycleRegistry的handleLifecycleEvent()方法 ,然後呼叫自身的onXXX()方法。
參照Android 架構元件(一)——Lifecycle, @ShymanZhu文中的時序圖:
我們從圖中可以看到,當Fragment將生命週期對應的事件交給其內部的Lifecycle處理後, LifecycleObserver (就是我們上文自定義的Presenter),就能夠接收到對應的生命週期事件,這是如何實現的呢?
2、LifecycleRegistry:Lifecycle
首先確認一點,LifecycleRegistry 就是 Lifecycle 的子類:
public class LifecycleRegistry extends Lifecycle {
}
複製程式碼
我們看一下 Lifecycle 類
public abstract class Lifecycle {
//註冊LifecycleObserver (比如Presenter)
public abstract void addObserver(@NonNull LifecycleObserver observer);
//移除LifecycleObserver
public abstract void removeObserver(@NonNull LifecycleObserver observer);
//獲取當前狀態
public abstract State getCurrentState();
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
}
複製程式碼
Lifecycle沒什麼要講的,幾個抽象方法也能看懂,作為Lifecycle的子類,LifecycleRegistry 同樣也能通過addObserver方法註冊LifecycleObserver (就是Presenter),當LifecycleRegistry 本身的生命週期改變後(可以想象,內部一定有一個成員變數State記錄當前的生命週期),LifecycleRegistry 就會逐個通知每一個註冊的LifecycleObserver ,並執行對應生命週期的方法。
我們看一下LifecycleRegistry 的handleLifecycleEvent()方法:
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
複製程式碼
看方法的名字我們就可以知道,handleLifecycleEvent方法會通過 getStateAfter 獲取當前應處的狀態並修改 Lifecycle本身的State 值,緊接著遍歷所 LifecycleObserver 並同步且通知其狀態發生變化,因此就能觸發LifecycleObserver 對應的生命週期事件。
實際上LifecycleRegistry 本身還是有很多值得一提之處,本文只闡述清楚原理,暫不涉及原始碼詳解。
一些小Tips
1、嘗試複用LifecycleRegistry
首先,LifecycleRegistry 本身就是一個成熟的 Lifecycle 實現類,它被例項化在Activity和Fragment中使用,如果我們需要自定義LifecycleOwner 並實現介面需要返回一個Lifecycle例項,完全可以直接在自定義LifecycleOwner中new一個LifecycleRegistry成員並返回它(簡而言之就是:直接拿來用即可)。
以下是Google官方文件:
LifecycleRegistry: An implementation of Lifecycle that can handle multiple observers. It is used by Fragments and Support Library Activities. You can also directly use it if you have a custom LifecycleOwner.
2、註解和DefaultLifecycleObserver的取捨
其次,Google的Lifecycle庫中提供了一個 DefaultLifecycleObserver 類,方便我們直接實現LifecycleObserver介面,相比較於文中demo所使用的註解方式,Google官方更推薦我們使用 DefaultLifecycleObserver 類,並宣告
一旦Java 8成為Android的主流,註釋將被棄用,所以介於DefaultLifecycleObserver和註解兩者之間,更推薦使用 DefaultLifecycleObserver 。
官方原文:
/*
* If you use <b>Java 8 Language</b>, then observe events with {@link DefaultLifecycleObserver}.
* To include it you should add {@code "android.arch.lifecycle:common-java8:<version>"} to your
* build.gradle file.
* <pre>
* class TestObserver implements DefaultLifecycleObserver {
* {@literal @}Override
* public void onCreate(LifecycleOwner owner) {
* // your code
* }
* }
* </pre>
* If you use <b>Java 7 Language</b>, Lifecycle events are observed using annotations.
* Once Java 8 Language becomes mainstream on Android, annotations will be deprecated, so between
* {@link DefaultLifecycleObserver} and annotations,
* you must always prefer {@code DefaultLifecycleObserver}.
*/
複製程式碼
* 3、Lifecycles 的最佳實踐
本小節內容節選自《[譯] Architecture Components 之 Handling Lifecycles》 作者:zly394 連結:juejin.im/post/5937e1…
-
保持 UI 控制器(Activity 和 Fragment)儘可能的精簡。它們不應該試圖去獲取它們所需的資料;相反,要用 ViewModel來獲取,並且觀察 LiveData將資料變化反映到檢視中。
-
嘗試編寫資料驅動(data-driven)的 UI,即 UI 控制器的責任是在資料改變時更新檢視或者將使用者的操作通知給 ViewModel。
-
將資料邏輯放到 ViewModel 類中。ViewModel 應該作為 UI 控制器和應用程式其它部分的連線服務。注意:不是由 ViewModel 負責獲取資料(例如:從網路獲取)。相反,ViewModel 呼叫相應的元件獲取資料,然後將資料獲取結果提供給 UI 控制器。
-
使用Data Binding來保持檢視和 UI 控制器之間的介面乾淨。這樣可以讓檢視更具宣告性,並且儘可能減少在 Activity 和 Fragment 中編寫更新程式碼。如果你喜歡在 Java 中執行該操作,請使用像Butter Knife 這樣的庫來避免使用樣板程式碼並進行更好的抽象化。
-
如果 UI 很複雜,可以考慮建立一個 Presenter 類來處理 UI 的修改。雖然通常這樣做不是必要的,但可能會讓 UI 更容易測試。
-
不要在 ViewModel 中引用View或者 Activity的 context。因為如果ViewModel存活的比 Activity 時間長(在配置更改的情況下),Activity 將會被洩漏並且無法被正確的回收。
總結
總而言之,Lifecycle還是有可取之處的,相對於其它架構元件之間的配合,Lifecycle更簡單且獨立(實際上配合其他元件味道更佳)。
本文旨在分析Lifecycle框架相關類的原理,將不會對Lifecycle每一行的原始碼進行深入地探究,如果有機會,筆者將嘗試寫一篇原始碼詳細解析。
參考&感謝
Lifecycle-aware Components 原始碼分析 @chaosleong
Android 架構元件(一)——Lifecycle @ShymanZhu
--------------------------廣告分割線------------------------------
關於我
Hello,我是卻把清梅嗅,如果您覺得文章對您有價值,歡迎 ❤️,也歡迎關注我的部落格或者Github。
如果您覺得文章還差了那麼點東西,也請通過關注督促我寫出更好的文章——萬一哪天我進步了呢?