Android 架構組件官方文檔01——LifeCycle

使用生命週期感知組件處理生命週期

支持生命週期的組件執行操做以響應另外一個組件(例如Activity和fragment)的生命週期狀態更改。這些組件可幫助您生成組織性更好,而且一般更輕量的代碼,這些代碼更易於維護。

常見的模式是在Activity和fragment的生命週期方法中實現依賴組件的操做。
可是,這種模式致使代碼的組織不良以及錯誤氾濫。經過使用生命週期感知組件,您能夠將相關組件的代碼從生命週期方法中移出並移入組件自己。html

android.arch.lifecycle包提供了類和接口,可以讓您構建支持生命週期的組件,這些組件可根據活動或片斷的當前生命週期狀態自動調整其行爲
注意:要將android.arch.lifecycle導入到Android項目中,請參閱向項目添加組件java

Android框架中定義的大多數應用程序組件都附帶有生命週期。生命週期由操做系統或您的流程中運行的框架代碼管理。它們是Android如何工做和應用程序必須尊重它們的核心。不這樣作可能會觸發內存泄漏甚至應用程序崩潰。android

// 若是使用的是java 8要顯示聲明以下的
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"

想象一下,咱們有一個在屏幕上顯示設備位置的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
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

儘管這個示例看起來很好,但在實際的應用程序中,您最終會有太多的調用來管理UI和其餘組件,以響應當前的生命週期狀態。
管理多個組件會在生命週期方法中放置大量代碼,例如onStart()和onStop(),這使得它們很難維護。網絡

此外,沒法保證組件在活動或片斷中止以前啓動。
若是咱們須要執行一個長時間運行的操做,好比onStart()中的一些配置檢查,狀況尤爲如此。
這可能會致使onStop()方法在onStart()以前完成的爭用條件,從而使組件的存活時間超過所需的時間。app

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();
    }
}

android.arch.lifecycle包提供的類和接口可幫助您以彈性和獨立的方式解決這些問題。框架

Lifecycle

Lifecycle是一個持有組件生命週期狀態(如Activity或Fragment)的信息的類,並容許其餘對象觀察此狀態。
Lifecycle使用兩個主要枚舉來跟蹤其關聯組件的生命週期狀態:編程語言

Event

  從框架和Lifecycle類派發的生命週期事件。
  這些事件映射到Activities和fragments中的回調事件。ide

State

  由Lifecycle對象跟蹤的組件的當前狀態。
圖片描述測試

將狀態視爲圖中的節點,將事件視爲這些節點之間的邊界。

一個類能夠經過向其方法添加註解來監視組件的生命週期狀態。
而後,您能夠經過調用Lifecycle類的addObserver()方法並傳遞觀察者的實例來添加觀察者,以下例所示:

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());

在上面的例子中,myLifecycleOwner對象實現了LifecycleOwner接口,這將在下一節中介紹。

LifecycleOwner

LifecycleOwner是一個單一的方法接口,表示該類有一個Lifecycle
它有一個方法getLifecycle(),它必須由class實現。
若是您試圖管理整個應用程序進程的生命週期,請參閱ProcessLifecycleOwner

該接口從各個類(如Fragment和AppCompatActivity)抽象生命週期的全部權,並容許編寫與它們一塊兒工做的組件。
任何自定義應用程序類均可以實現LifecycleOwner接口

實現LifecycleObserver的組件能夠與實現LifecycleOwner的組件無縫協做,由於全部者能夠提供生命週期,觀察者能夠註冊觀察。

對於位置跟蹤示例,咱們可使MyLocationListener類實現LifecycleObserver,而後使用onCreate()方法中的活動生命週期對其進行初始化。
這容許MyLocationListener類是自給自足的,這意味着對生命週期狀態變化做出反應的邏輯在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();
            }
        });
  }
}

一個常見的用例就是避免在生命週期狀處於很差的狀態時調用某些回調。
例如,若是回調在保存活動狀態後(我本身理解爲onSaveInstanceState()方法執行後,也就是fragment不存在)運行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的LocationListener,咱們只須要初始化它。
全部的啓動和銷燬操做都由該類自己進行管理。

若是Library提供須要與Android生命週期配合使用的類,咱們建議您使用支持生命週期的組件。
您的Library客戶端能夠在客戶端無需手動生命週期管理便可輕鬆集成這些組件。

實施自定義LifecycleOwner

Support Library 26.1.0中的Fragment和Activity以及更高版本已經實現LifecycleOwner接口。

若是您想要建立LifecycleOwner的自定義類,則可使用LifecycleRegistry類,但須要將事件轉發到該類中,如如下代碼示例所示:

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;
    }
}

生命週期感知組件的最佳實踐

  • 儘量保持您的UI控制器(Activities和Fragments)儘量精簡。他們不該該試圖獲取他們本身的數據;相反,使用ViewModel來作到這一點,並觀察一個LiveData對象來反映更改回視圖。
  • 嘗試編寫數據驅動UI的界面,其中您的UI控制器的職責是在數據更改時更新視圖,或將用戶操做通知給ViewModel
  • 把你的數據邏輯放在ViewModel類中。ViewModel應做爲您的UI控制器和其餘應用程序之間的鏈接器。但要當心,ViewModel不負責提取數據(例如,來自網絡)。相反,ViewModel應調用相應的組件來獲取數據,而後將結果提供給UI控制器。
  • 使用Data Binding在視圖和UI控制器之間保持乾淨的界面。這使您可使您的視圖更具說明性,並最大限度地減小須要在活動和片斷中編寫的更新代碼。若是你喜歡用Java編程語言來作到這一點,可使用像Butter Knife這樣的庫來避免樣板代碼而且有更好的抽象
  • 若是您的UI很複雜,請考慮建立一個presenter類來處理UI修改。這多是一項艱鉅的任務,但它可使您的UI組件更易於測試。
  • 避免在ViewModel中引用View或Activity上下文。若是ViewModel超出活動(在配置更改的狀況下),則活動會泄漏而且垃圾收集器沒法正確處理。

支持生命週期感知組件的用例

支持生命週期的組件可讓您在各類狀況下更容易地管理生命週期。
一些例子是:

  • 在粗粒度和細粒度 位置更新之間切換。使用生命週期感知組件在位置應用可見時啓用細粒度位置更新,並在應用處於後臺時切換到粗粒度更新。LiveData是一種生命週期感知型組件,容許您的應用在用戶更改位置時自動更新用戶界面。
  • 中止並開始視頻緩衝。儘量使用支持生命週期的組件來啓動視頻緩衝,但延遲播放直到應用程序徹底啓動。您還可使用生命週期感知組件在應用程序銷燬時終止緩衝。
  • 啓動和中止網絡鏈接。使用支持生命週期的組件能夠在應用程序處於前臺時實時更新(流式傳輸)網絡數據,並在應用程序進入後臺時自動暫停。
  • 暫停和恢復動畫可繪製。使用生命週期感知組件處理在應用程序處於後臺時暫停動畫的可繪製畫面,並在應用程序處於前景時恢復可繪製畫面。

處理中止事件

當Lifecycle屬於AppCompatActivity或Fragment時,Lifecycle的狀態將更改成CREATED,並在調用AppCompatActivity或Fragment的onSaveInstanceState()時調度ON_STOP事件。

當Fragment或AppCompatActivity的狀態經過onSaveInstanceState()保存時,UI被認爲是不可變的,直到ON_START被調用。嘗試在保存狀態後修改UI界面可能會致使應用程序的導航狀態不一致,這就是爲何若是應用程序在狀態保存後運行FragmentTransaction時FragmentManager會拋出異常。
有關詳細信息,詳情請參閱 commit()

若是觀察者的關聯Lifecycle在STARTED以前,則LiveData經過避免調用其觀察者來防止這種邊緣狀況出現。
在幕後,它決定調用觀察者以前調用isAtLeast()

不幸的是,AppCompatActivity的onStop()方法會在onSaveInstanceState()以後調用,這會在不容許UI狀態更改但生命週期還沒有移至CREATED狀態的狀況下留下空隙。

爲了防止出現這個問題,beta2版本中的Lifecycle類將lower狀態標記爲CREATED而不分派事件,即便事件直到onStop()被調用也未被分派,任何檢查當前狀態的代碼也都會得到真實值。

不幸的是,這個解決方案有兩個主要問題:

  • 在API等級23或更低的狀況下,Android系統實際上保存活動的狀態,即便它被另外一活動部分覆蓋。換句話說,Android系統調用onSaveInstanceState(),但不必定調用onStop()。這會建立一個潛在的長時間間隔,即便其UI狀態無​​法修改,觀察者仍認爲生命週期處於活動狀態。
  • 任何想要向LiveData類公開相似行爲的類都必須實現Lifecycle beta2和更低版本提供的解決方法

注意:爲了使此流程更簡單,並提供與舊版本的更好兼容性,從版本1.0.0-rc1開始,在調用onSaveInstanceState()而無需等待對onStop()的調用時,將Lifecycle對象標記爲CREATED,並調度onStop()方法。這不太可能影響您的代碼,但您須要注意這一點,由於它與API級別26及更低級別的Activity類中的調用順序不匹配。

相關文章
相關標籤/搜索