[譯] Architecture Components 之 Handling Lifecycles

【目錄】

1. Architecture Components 之 Guide to App Architecture

2. Architecture Components 之 Adding Components to your Project

3. Architecture Components 之 Handling Lifecycles

4. Architecture Components 之 LiveData

5. Architecture Components 之 ViewModel

6. Architecture Components 之 Room Persistence Library

示例代碼連接


處理生命週期

android.arch.lifecycle 包提供了能夠用於構建生命週期感知(lifecycle-aware)組件的類和接口,這些組件能夠根據 Activity 或 Fragment 的當前生命週期自動調整其行爲。javascript

注:導入 android.arch.lifecycle 到項目中請參看添加組件到項目html

Android Framework 中定義的大多數應用程序組件都附有生命週期。這些生命週期由操做系統或在進程中運行的框架代碼管理。它們是 Android 運行的核心而且應用程序必須遵照它們,不這樣作可能會致使內存泄漏甚至應用程序崩潰。java

假設咱們有一個須要在屏幕上顯示設備位置的 Activity。常見的實現方式可能以下所示:android

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // 連接到系統定位服務
    }

    void stop() {
        // 斷開系統定位服務
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // 更新 UI
        });
  }

    public void onStart() {
        super.onStart();
        myLocationListener.start();
    }

    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}複製代碼

儘管這個例子看起來不錯,在真正的應用程序中,你最終會有太多的相似調用而且會致使 onStart() 和 onStop() 方法變的很是臃腫。git

另外,一些組件不能在 onStart() 方法中當即啓動。若是咱們須要在啓動位置觀察者以前檢查一些配置怎麼辦?在某些狀況下極可能發生 Activity 中止後才檢查配置完成,這意味着在 myLocationListener.stop() 被調用以後 myLocationListener.start() 才被調用,會致使定位服務基本上永遠保持鏈接。github

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // 更新 UI
        });
    }

    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // 若是這個回調在 Activity 中止後被調用怎麼辦?
            if (result) {
                myLocationListener.start();
            }
        });
    }

    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}複製代碼

android.arch.lifecycle 包提供了類和接口幫助以彈性和隔離的方式解決這些問題。網絡

Lifecycle

Lifecycle 是一個類,它持有關於組件(如 Activity 或 Fragment)生命週期狀態的信息,而且容許其餘對象觀察此狀態。app

Lifecycle 使用兩個主要的枚舉來跟蹤其關聯組件的生命週期狀態。框架

Eventide

生命週期事件是從框架和 Lifecycle 發出的事件。這些事件映射到 Activity 和 Fragment 中的回調事件。

State

Lifecycle 對象跟蹤的組件的當前狀態。

將狀態視爲圖表的節點,事件做爲這些節點之間的邊緣。

類能夠經過向其方法添加註釋來監控組件的生命週期狀態。

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());複製代碼

LifecycleOwner

LifecycleOwner 是一個單一方法的接口,它表示實現類具備一個 Lifecycle。它有一個 getLifecycle()) 方法,該方法必須由實現類實現。

該實現類從個別的類(例如 Activity 和 Fragment)提取生命週期的全部權,而且容許編寫可與二者兼容的組件。任何自定義應用程序類均可以實現 LifecycleOwner 接口。

注:因爲 Architecture Components 處於 alpha 階段,因此 FragmentAppCompatActivity 不能實現 LifecycleOwner (由於咱們不能在穩定的組件中添加依賴不穩定的API)。在 Lifecycle 穩定以前,爲了方便提供了 LifecycleActivityLifecycleFragment 類。在 Lifecycles 項目發佈後,支持庫中的 Fragment 和 Activity 將會實現 LifecycleOwner 接口;屆時 LifecycleActivityLifecycleFragment 將會被棄用。另請參閱在自定義 Activity 和 Fragment 中實現 LifecycleOwner

對於上面的例子,咱們可使 MyLocationListener 類成爲 LifecycleObserver 而後在 onCreate 中使用 Lifecycle 初始化它。這樣讓 MyLocationListener 類自給自足,意味着在必要的時候它能對本身進行清理。

class MyActivity extends LifecycleActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // 更新 UI
        });
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}複製代碼

一個常見的用例是避免在 Lifecycle 處於不良狀態時調用某些回調。例如,若是在保存 Activity 狀態後回調運行 Fragment 事務,將會致使崩潰,所以咱們永遠不會想要調用該回調。

爲了簡化該用例, Lifecycle 類容許其餘對象查詢當前狀態。

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) {
           // 鏈接
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getState().isAtLeast(STARTED)) {
            // 若是沒有鏈接則進行鏈接
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // 若是已經鏈接則斷開鏈接
    }
}複製代碼

經過這種實現,LocationListener 類是徹底的生命週期感知(lifecycle-aware);它能夠進行本身的初始化或清理操做,而不受其 Activity 的管理。若是須要在其它的 Activity 或其餘的 Fragment 中使用 LocationListener,只須要初始化它。全部的安裝和卸載操做都由類本身管理。

能夠與 Lifecycle 一塊兒使用的類稱爲生命週期感知(lifecycle-aware) 組件。鼓勵有須要使用 Android 生命週期的類的庫提供生命週期感知(lifecycle-aware) 組件,以便於用戶能夠輕鬆的在客戶端集成這些類,而不須要手動管理生命週期。

LiveData 是一個生命週期感知(lifecycle-aware) 組件的示例。與 ViewModel 一塊兒使用 LiveData 能夠在遵照 Android 生命週期的前提下,更容易地使用數據填充UI。

Lifecycles 的最佳實踐

  • 保持 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 將會被泄漏而且沒法被正確的回收。

附錄

在自定義 Activity 和 Fragment 中實現 LifecycleOwner

任何自定義的 Fragment 或 Activity 均可以經過實現內置的 LifecycleRegistryOwner 接口轉換爲 LifecycleOwner(而不是繼承 LifecycleActivityLifecycleFragment

public class MyFragment extends Fragment implements LifecycleRegistryOwner {
    LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}複製代碼

若是要建立一個 LifecycleOwner 的自定義類,可使用 LifecycleRegistry 類,可是須要將事件轉發到該自定義類中。若是是 Fragment 和 Activity 實現了 LifecycleRegistryOwner 接口,則此轉發會自動完成。

相關文章
相關標籤/搜索