Android架構(gòu)組件學(xué)習(xí)之LifeCycle

英文源址 Android架構(gòu)組件之lifecyle
Lifecycle-aware(生命周期感知型)組件能夠響應(yīng)其他組件的生命周期變化,例如activitiy和fragment.這樣的組件能夠讓你更好的組織代碼,而且他們顯得更輕量,更容易維護.

一個常見的場景就是,我們需要在activitiy或是fragment中在生命周期方法中實現(xiàn)相關(guān)的組件方法.總的來說,這種情況導(dǎo)致了代碼在組織上比較差,而且會導(dǎo)致一些分散的錯誤.通過使用生命周期感知型組件,你可以將這些在生命周期方法中實現(xiàn)的代碼移除,在組件內(nèi)部實現(xiàn)即可(更大程度的實現(xiàn)了組件之間的解耦合);

android.arch.lifecycle 這個包里面,Android 為我們提供了可以讓你構(gòu)建生命周期感知型的組件的 類和相關(guān)接口.

備注:

如果想使用android.arch.lifecycle 包里面的功能詳見adding components to your project.

Android framework里面的大多數(shù)APP組件都是帶有生命周期熟悉的.你程序里面的組件生命周期都是被操作系統(tǒng)或是framework(框架層,俗稱中間件)來管理的.這些組件對于你的APP運行穩(wěn)定來說至關(guān)重要.不應(yīng)該對這些組件進行操作,因為可能會導(dǎo)致內(nèi)存泄露,嚴重的話還會導(dǎo)致程序崩潰.

想象一下我們有一個顯示位置的activity,一般來說我們采用如下所示的實現(xiàn):

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

盡管上述代碼看起來并沒啥問題,但是在實際開發(fā)中為了響應(yīng)當前生命周期變化,你需要添加很多額外代碼來管理UI接其他組件.在例如

onStart()onStop() 這樣的生命周期中管理多個組件讓維護顯得很困難.此外,我們在activitiy或是fragment已經(jīng)是stop前并不能保證組件啟動.這種情況很常見,在我們需要一個長時間運行的操作時候,例如在onStart() 方法中進行參數(shù)校驗工作.如果 onStop()onStart() 之前結(jié)束了,這樣會導(dǎo)致一個競爭條件(多線程,或者因執(zhí)行順序?qū)е聰?shù)據(jù)結(jié)果).該情況的出現(xiàn)會讓這個組件(myLocationListener)生命周期超出其需要的時間.

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();//myLocationListener 老子又回來啦
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();//老子掛了
    }
}

android.arch.lifecycle 包提供了一些類和接口來用比較柔和藕性低的方式幫助你解決這些問題.

Lifecycle


Lifecycle 是用來保存組件(例如 activity or a fragment) 生命周期狀態(tài)的類,該類允許其他對象感知這個狀態(tài).

Lifecycle 在每個相關(guān)的組件中使用兩個枚舉類來追蹤生命周期狀態(tài).

Event(事件)

由framework和 Lifecycle 類分發(fā)的生命周期事件.

State(狀態(tài))

Lifecycle 類持有的當前組件的狀態(tài).

image

按圖思考一下圖標上節(jié)點之間的狀態(tài)和事件.

有個類可以通過添加注解的方法監(jiān)控組件的生命周期狀態(tài).你可以為實現(xiàn)Lifecycle 接口的組件調(diào)用addObserver() 方法,來講獲得一個observer對象.示例代碼如下.

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 對象實現(xiàn)了 LifecycleOwner 接口,我們下面就來說說這個接口.

LifecycleOwner


LifecycleOwner 是一個只含有一個方法的接口,該類表示這個類含有一個Lifecycle .這個接口有一個叫做getLifecycle() 的方法.如果你想要管理生個APP的生命周期,那么看看ProcessLifecycleOwner.

這個接口把像FragmentAppCompatActivity 這樣的類和生命周期之間進行抽象,允許針對這些類(fragment 和activity)書寫一些組件.自定義的application都可以實現(xiàn)這個接口.

實現(xiàn)了 LifecycleObserver 接口的組件?可以和實現(xiàn)了LifecycleOwner 組件進行無縫連接,因為一個可以提供lifecycle,另一個可以觀察lifecycle.

就拿地址追蹤為例,我們可以讓MyLocationListener實現(xiàn)LifecycleObserver 然后在onCreate() 方法中使用activity的 Lifecycle 進行初始化. 這樣 MyLocationListener類便可以不要依賴activity實現(xiàn)完全的邏輯控制,達到自給自足.有了這些相對獨立的組件,管理activity和fragment邏輯講變得更簡便.

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

一個常見的案例就是如果生命周期狀態(tài)不穩(wěn)定避免調(diào)用相關(guān)的回調(diào). 例如當回調(diào)在activity 狀態(tài)保存后運行fragment transaction,將導(dǎo)致crash(不了解的同學(xué),復(fù)習(xí)一下fragment),有了這個接口之后再也不會再錯誤狀態(tài)下調(diào)用這個回調(diào)了.

為了更好的使用,Lifecycle 類允許其他對象能夠查詢當前狀態(tài).

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

有了這個實現(xiàn),我們的LocationListener實現(xiàn)了完全的生命周期感知.如果我們想要在其他的activity或者fragment中使用它,我們只需要對其進行初始化即可.

如果一個library需要處理與生命周期相關(guān)的任務(wù),那么我建議使用生命周期感知型組件.你的library能夠輕易的管理生命周期,而不需要手工的寫很多代碼.

實現(xiàn)自定義的 LifecycleOwner

在Support Library 26.1.0以上的fragment和activity已經(jīng)實現(xiàn)了LifecycleOwner 接口.

如果你又一個自定義類的,你想自己實現(xiàn)一個LifecycleOwner,你可以使用LifecycleRegistry類(LifecycleRegistry是lifecyle 類的子類,activity 和 fragment也是通過該類實現(xiàn)提供lifecycle對象),但是你需要將事件注入到該類里面,示例代碼如下所示:

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控制器盡量精簡,他們不應(yīng)該自己去請求處理數(shù)據(jù),應(yīng)該使用ViewModel去處理數(shù)據(jù),觀察一個LiveData
    對象,并且將數(shù)據(jù)變化反應(yīng)到試圖上.

  • 嘗試使用數(shù)據(jù)驅(qū)動型的UI,你的UI控制器相應(yīng)數(shù)據(jù)變化,并且改變view ,或者通知user返回ViewModel

  • 將你的數(shù)據(jù)邏輯放入ViewModel
    ViewModel應(yīng)該作為你的UI控制層和其他層的連接器,但是請狐疑獲取網(wǎng)絡(luò)數(shù)據(jù)不是viewmodel的職責.相反viewmodel 應(yīng)該讓組件去獲取數(shù)據(jù),然后處理結(jié)果返回給UI控制層.

  • 使用Data Binding 來在view和UI控制層直接維護一個簡潔的接口.這可以允許你講view更多的是聲明式的,最小化更新代碼.如果你想要這么做,可以使用Butter Knife 來獲得更好的抽象.

  • If your UI is complex, consider creating a
    presenter
    class to handle UI modifications. This might be a laborious task, but it can make your UI components easier to test.

  • 如果你的UI界面相對復(fù)雜,考慮創(chuàng)建一個presenter 來處理UI 變化,這么做可能看起來工作量提升不少,不過這個讓你的UI組將更容易測試.

  • ViewModel中避免使用view,activity,fragment的,這樣可以避免內(nèi)存泄露.

lifecycle-aware components使用場景


生命周期感知型的組件可以讓管理生命變得更加簡單,下面有幾個例子:

  • 在高精度和低精度地理位置之間的切換.使用生命周期感知型的組件能夠使用高精度獲取地理位置在你的APP可見時候,當你的APP切換到后臺的時候使用低精度更新.

  • 啟動和關(guān)閉視頻緩沖.使用生命周期感知型組件來打開視頻緩沖.你也可以在在app關(guān)閉的時候關(guān)閉視頻緩沖.

  • 啟動和關(guān)閉網(wǎng)絡(luò)連接.使用生命周期感知型組件能夠允許app在前臺時候更新網(wǎng)絡(luò)數(shù)據(jù),在app在后臺時候自動暫停.

  • 暫停和重啟動畫,

處理 stop 事件


當一個lifecyle 屬于AppCompatActivity或者Fragment 時,調(diào)用onSaveInstanceState(),方法, Lifecycle 狀態(tài)變成 CREATED ,分發(fā)ON_STOP .

當fragment 或者AppCompatActivity狀態(tài)在onSaveInstanceState() 保存了,他的界面就會被認為不可以改變,直到 ON_START 事件被調(diào)用. 在state被保存后修改UI,會因狀態(tài)的不連續(xù)產(chǎn)生異常.這是為什么在app 狀態(tài)被保存后運行FragmentTransaction 會報異常.

LiveData 避免了這些邊緣性案例的產(chǎn)生,它通過觀察相關(guān)的LifeCycle 狀態(tài)是不是STARTED.在這個場景下它在調(diào)用observer之前調(diào)用了一個isAtLeast()

不幸的是,AppCompatActivityonStop( ) 方法在onSaveInstanceState() 之后被調(diào)用, 這會導(dǎo)致UI狀態(tài)狀態(tài)改變的時候留下一個空白期.

為了避免這個問題,Lifecycle 類在beta2 版本和更低的版本 標記狀態(tài)為 CREATED ,這樣任何代碼都能檢查當前狀態(tài),并且獲得真是的值,知道onStop被系統(tǒng)調(diào)用.

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

  • 在Api 23以下,Android 系統(tǒng)保存狀態(tài)即便activity被復(fù)寫了.換句話說,Android系統(tǒng)調(diào)用onSaveInstanceState()但是不必調(diào)用onstop.這會產(chǎn)生一個潛在問題,有個時間段observer還認為生命周期處于活躍狀態(tài),但是事實UI狀態(tài)不能被更改了.

  • 任何想要實現(xiàn)LiveData 類 的類似功能都要實現(xiàn)Lifecycle beta2 或以下的版本.

備注:

為了讓整個流程更加簡單,提供更好的兼容性,使用1.0.0-rc1 版本,

Lifecycle 對象會被標記成CREATED(狀態(tài))和ON_STOP(事件) 如果onSaveInstanceState() 被調(diào)用時,而不需要等到onStop()方法.這一般對你的代碼不會造成什么影響,不過你還是應(yīng)該知道在 API 26 及以下順序和你想象的有些區(qū)別.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容