1. 程式人生 > >Android官方架構元件介紹之Lifecycle的使用詳解

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之後的版本。