Android官方架構元件介紹之Lifecycle的使用詳解
Lifecycle 是用來管理和響應activity和Fragment生命週期的變化。我們通常在Activity和Fragment中生命週期方法中進行一些繁重操作,幫我們可以將這些生命週期的方法使用Lifecycle進行管理。它可以自動整合Activity和Fragment生命週期的狀態。
新增依賴:
1.在project下的build.gradle中新增Maven倉庫
allprojects {
repositories {
jcenter()
google()//新增Google Maven倉庫
}
}
2.app下的build.gradle
dependencies { // ViewModel and LiveData implementation "android.arch.lifecycle:extensions:1.1.1" // alternatively, just ViewModel implementation "android.arch.lifecycle:viewmodel:1.1.1" // alternatively, just LiveData implementation "android.arch.lifecycle:livedata:1.1.1" annotationProcessor "android.arch.lifecycle:compiler:1.1.1" // Room (use 1.1.0-beta3 for latest beta) implementation "android.arch.persistence.room:runtime:1.0.0" annotationProcessor "android.arch.persistence.room:compiler:1.0.0" // Paging implementation "android.arch.paging:runtime:1.0.0-rc1" // Test helpers for LiveData testImplementation "android.arch.core:core-testing:1.1.1" // Test helpers for Room testImplementation "android.arch.persistence.room:testing:1.0.0" }
3.新增Java 8 支援
dependencies {
// Java8 support for Lifecycles
implementation "android.arch.lifecycle:common-java8:1.1.1"
}
4.RXJava支援依賴
dependencies { // RxJava support for Room (use 1.1.0-beta3 for latest beta) implementation "android.arch.persistence.room:rxjava2:1.0.0" // ReactiveStreams support for LiveData implementation "android.arch.lifecycle:reactivestreams:1.1.1" // RxJava support for Paging implementation "android.arch.paging:rxjava2:1.0.0-alpha1" }
5.Guava依賴支援
dependencies {
// Guava support for Room
implementation "android.arch.persistence.room:guava:1.1.0-beta3"
}
6.輕量級Lifecycles支援dependencies { // Lifecycles only (no ViewModel or LiveData) implementation "android.arch.lifecycle:runtime:1.1.1" annotationProcessor "android.arch.lifecycle:compiler:1.1.1" }
應用的生命週期大部分都是定義在Android Framework層,生命週期的管理是在作業系統或者是專案的框架層進行處理。否則會引發記憶體洩漏或者直接崩潰。例如: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 管理Activity的其他響應
}
@Override
public void onStop() {
super.onStop();
myLocationListener.stop();
// manage other components that need to respond
// to the activity lifecycle
}
}
然而在實際專案中,我們會有很多管理UI的回撥和其他的響應生命週期的元件,在生命週期方法中會有很多很複雜的邏輯,不利於我們專案的維護。也不能保證Activity或Fragment在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();
}
}
Lifecycle
Lifecycle不僅包含生命週期的狀態資訊,允許其他物件監聽這個狀態。
它使用兩個列舉來關聯生命週期的狀態:
事件:其從Fragmentwork層和Lifecycle類開始分發事件,再將這些事件對映到Activity和Fragment的生命週期中
狀態:狀態就是跟蹤的生命週期的狀態。
類的生命週期狀態需要通過註解的方式。如下
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());
ps:myLifecycleOwner物件是實現了LifecycleOwner介面的物件
LifecycleOwner
LifecycleOwner是一個只有一個getLifecycle()的介面。此外還有一個可以控制整個應用的類
這個介面擁有抽象了Lifecycle這個單獨類的所有權,此介面對任何類都可以實現。
LicecycleObserver和LicecycleOwner一起使用一個用來提供生命週期,一個用來註冊觀察者觀察
示例如下:
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();
}
});
}
}
但是假如有類似於Fragment的事物執行回撥在Activity狀態被釋放掉之後開啟或者做其他事情,這就是我們不希望看到的,所以我們 要做讓Fragment的不回撥。如下:
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中使用,只需要對他初始化就行。這樣所有的操作都會交由它本類來處理。
自定義LifecycleOwner
自定義實現LifecycleOwner必須在在Support Library26.1.0之的版本進行實現
使用LifecycleRegistry將事件推進到自定義的LifecycleOwner中。
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;
}
}
感知元件的最佳實踐
1.保持Activity或Fragment的簡潔,使用ViewModel來觀察data和View
2.嘗試編寫資料驅動的UI,資料或者使用者行為發生改變UIController會更新View,或者通知ViewModel
3.ViewModel時Google設計的專門用於Model層和View層進行互動的一個類,與資料相關的邏輯Google推薦使用ViewModel去做,PS:ViewModel本身是不能操作資料的,它的本質是通過呼叫相關的元件來通知UI controller.
4.使用Data Binding或者Butter Knife節省模板程式碼的抽取。
5.使用MVP模式進行解耦
6.避免在ViewModel中引用View或Activity的上下文,防止記憶體洩漏。
感知元件的用例
1.實現粗粒度和細粒度直接的切換。當Activity可見狀態是切換為細粒度,當其退居到後臺(即不可見)是開啟粗粒度。LiveData這個類當用戶的行為發生改變時,它會自動通知UI更新。
2.終止和開啟視訊緩衝。Licecycle-aware會在開始播放之前儘快的緩衝,在銷燬時終止緩衝。
3.開啟和停止網路連線。應用在前臺或者後臺是會自動連線網路或斷開。
4.暫停和播放動畫。應用在前臺時會自動播放或暫停。
停止事件處理
當Lifecycle屬於AppCompatActivity或Fragment時,其狀態CREATE和ON_STOP的事件的分發是在APPCompatActivity或Fragment的onSaveInstanceState()被呼叫。
當ON_START被呼叫之前,同時Fragment或AppCompatActivity的狀態會儲存在onSaveInstanceState()中。
PS:如果在UI的狀態儲存過之後FragmentManger會拋異常。
如果觀察者在STARTRD時或者之前關聯Lifecycle,LiveData通過避免呼叫它的觀察者來阻止這個邊緣案例的出現。並且在isAtLeast()之前通知其觀察者。
在beta2版本之前,AppCompatActivity在其onSaveInstanceState()之後,並且onStop()呼叫之前去跟新UI,Lifecycle此時處於未建立狀態。bata2之後會在事件分發之前去檢查Lifecycle的狀態,獲取此時實際的狀態。
但是還有兩個問題:
1.在API level 23之前或者更低版本下,Android系統即便被另一個Activity覆蓋,它還是會儲存上一個的狀態。也就是說onSaveinstanceState()被呼叫了可能沒有呼叫onStop()。這就產生了一個潛在的長時間間隔,觀察者仍然認為Lifecycle是活動的,即它的UI狀態不能被修改。
2.只要使用LiveData就必須使用beta2之後的版本。