萬物基于Lifecycle!

零. 前言

關于Jetpack的組件使用已經很久了,其原理一直處于碎片化接受的狀態,最近項目不忙,現進行完整的一次梳理,首先看看The base -- Lifecycle。

一. Everything is based on Lifecycle

Lifecyle的地位在整個架構中處于最底層的基石,有了它才有后續的LiveData和ViewModel。

Lifecyle出現的背景

  1. Android中有一個比較重要的概念 -- 生命周期,大到Application,小至Fragment都會遵循其本身的聲明周期規則。
  2. 生命周期感知組件--即需要遵循生命周期規則在特定的生命周期內做對應的事,但它沒法直接感知,所以需要借助Activity或者Fragment通過復寫其生命周期方法,來進行維護。這種模式有著顯而易見的缺陷--代碼條理性差、不內聚、使得V層代碼越發臃腫。
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
    }
}

上面引用官網文檔上舉的一個例子,希望activity在前臺時進行定位的監聽,所以復寫了onStart()方法和onStop()方法,并分別開始定位和停止定位。
問題:

  1. 實際項目中這種相關場景的依賴生命周期的組件非常多,這無疑是令人頭大的。
  2. 此外還有內存泄漏的可能,如果onStart中該組件需要進行耗時操作,則可能出現OnStop方法在onStart方法先走,如此該組件留存時間就會比其所需時間長,這種競爭的情況就可能會導致內存泄漏的情況發生。

二. How to use Lifecycle ?

It's so easy!

step1: 添加依賴:

   dependencies {
        def lifecycle_version = "2.2.0"
        def arch_version = "2.1.0"

        // Lifecycles only (without ViewModel or LiveData)
        implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"


        // Annotation processor
        annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // alternately - if using Java8, use the following instead of lifecycle-compiler
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
    }

step2: 將需要感知生命周期的組件實現對應接口,共3種途徑

  1. 實現DefaultLifecycleObserver接口

     public interface DefaultLifecycleObserver extends FullLifecycleObserver {
         void onCreate(LifecycleOwner owner);
         void onStart(LifecycleOwner owner);
         void onResume(LifecycleOwner owner);
         void onPause(LifecycleOwner owner);
         void onStop(LifecycleOwner owner);
         void onDestroy(LifecycleOwner owner);
     }
     
     class LocationObserver implements DefaultLifecycleObserver{
         void onStart(LifecycleOwner owner){}
         void onStop(LifecycleOwner owner){}
     }
    
  2. 繼承LifecycleObserver類

    //1. 自定義的LifecycleObserver觀察者,在對應方法上用注解聲明想要觀  察的宿主的生命周期事件即可
    class LocationObserver extends LifecycleObserver{
        //宿主執行了onstart時,會分發該事件
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        void onStart(@NotNull LifecycleOwner owner){
        //開啟定位
        }
    
        //宿主執行了onstop時 會分發該事件
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        void onStop(@NotNull LifecycleOwner owner){
            //停止定位
        }
        }
    
  3. 實現LifecycleEventObserver

     class LocationObserver extends LifecycleEventObserver{
         @override
         void onStateChanged(LifecycleOwner source, Lifecycle.Event event){
         //需要自行判斷life-event是onstart, 還是onstop
         }
     }
    

step3:

在生命周期組件中綁定對應生命周期觀察者
```
    //2. 注冊觀察者,觀察宿主生命周期狀態變化
    class MyFragment extends Fragment{
        public void onCreate(Bundle bundle){
            LocationObserver observer =new LocationObserver()
            getLifecycle().addObserver(observer);
        }
    }
```

至此,如果看到至此,其實你就已經學會了lifecycle的用法了,合理地使用lifecycle可以輕松地管理我們應用的生命周期,優雅地實現業務,結合viewModel和liveData使用會更加酸酸!!

但上述的例子僅僅是lifecyle的基礎用法,如果想要玩出更加酷炫的花樣,則需要進一步了解其背后的原理。

三. 掀起Lifecycle的蓋頭來!

1.核心職能類

首先我們先要知道四個核心類,分別為LifecycleOwner、 Lifecycle、 LifecyleRegistry、 LifecycleObserver,他們之間的關系和職能我們用下表來捋一捋。

類名 職責
Lifecycle 一個抽象類,定義了State(宿主狀態)、Event(分發的生命周期事件),能添加和移除宿主生命周期的觀察者
LifecyleRegistry Lifecycle的唯一實現類,負責生命周期的注冊及分發
LifecycleOwner 生命周期的宿主,持有Lifecycle的類,需要實現getLifecycle方法
LifecycleObserver 感知宿主生命周期的觀察者,通過生命周期事件獲得對應的宿主生命周期狀態
核心職能類UML圖.jpg

上面表格及類圖已經清晰地顯示了對應幾個核心類之間的關系和職責,其中提及到的宿主狀態和生命周期事件。


2. 宿舍生命周期狀態與生命周期事件

下面我們引用官網上的一幅圖來簡單描述一下宿主狀態和生命周期事件

生命周期狀態示意圖.png
  • State:狀態,是Lifecycle中對應Activity生命周期的一種狀態標識,共INITIALIZED、DESTROYED、CREATED、STARTED、RESUMED五種狀態

  • Event:事件,當State發生變化時,Lifecycle會向已注冊的LifecycleObserver發送事件,例如:當State從INITIALIZED變化到CREATED時,就會發出ON_CREATE事件。


經過上面的介紹,我們應該就能看出來,要真正弄懂Lifecycle,其實就是需要弄懂三件事

  1. 狀態(State)如何和組件(Activity、Fragment)生命周期綁定的?
  2. 觀察者咋注冊上的?
  3. 如何分發生命周期事件Event到觀察者?

3.Fragment和Activity是如何實現Lifecycle的?

? Fragment實現了宿主接口LifecycleOwner,利用注冊器LifecycleRegistry進行分發對應的事件給每個觀察者

public class Fragment implements LifecycleOwner {
    LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
      @Override
      public Lifecycle getLifecycle() {  
          //復寫自LifecycleOwner,所以必須new LifecycleRegistry對象返回
          return mLifecycleRegistry;
      }

    void performCreate(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
      }

     void performStart(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
      }
      .....
     void performResume(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
      }  
}

? Activity實現的Lifecycle需要借助一個Fragment--ReportFragment(這是一個透明的Fragment)來用以報告生命周期的變化,這里有一個問題,為什么Activity不直接和Fragment一樣直接在對應自身的生命周期方法處分發生命周期事件呢?這個問題在文末解答

public class ComponentActivity extends Activity implements LifecycleOwner{
  private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
   @NonNull
   @Override
   public Lifecycle getLifecycle() {
      return mLifecycleRegistry;
   }
  
  protected void onCreate(Bundle bundle) {
      super.onCreate(savedInstanceState);
      //往Activity上添加一個fragment,用以報告生命周期的變化
      //目的是為了兼顧不是繼承自AppCompactActivity的場景.
      ReportFragment.injectIfNeededIn(this); 
}

ReportFragment本身沒有什么特殊的地方,和Fragment中源碼一樣,在各個生命周期方法內利用mLifecycleRegistry分發事件。

  public class ReportFragment extends Fragment{
    public static void injectIfNeededIn(Activity activity) {
        android.app.FragmentManager manager =  activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(),                                    REPORT_FRAGMENT_TAG).commit();
            manager.executePendingTransactions();
        }
    }
    @Override
    public void onStart() {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }
    @Override
    public void onResume() {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }
    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
    }
    private void dispatch(Lifecycle.Event event) {
         Lifecycle lifecycle = activity.getLifecycle();
         if (lifecycle instanceof LifecycleRegistry) {
             ((LifecycleRegistry)   lifecycle).handleLifecycleEvent(event);
         }
}

4.觀察者咋注冊上的?

前面我們已經提到過,LifecycleRegistry--這個唯一實現了Lifecycle的類,它即是一個注冊中心兼分發中心,替Activity和Fragment代理了生命周期事件的注冊和分發。

(為什么不讓Activity自己來做這件事呢?我覺得是為了類的職責單一原則和及迪米特原則,Activity屬于View層,它只需要管理如何展示即可。)

public void addObserver(@NonNull LifecycleObserver observer) {
        // 添加新的Observer時,會首先根據宿主的狀態計算出它的初始狀態,只要不是在onDestroy中注冊的,它               // 的初始狀態都是INITIALIZED
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        // 接著會把observer包裝成ObserverWithState,這個類主要是包含了觀察者及其狀態。
        // 每個事件都會經由這個對象類轉發,這個類后面會來分析
        ObserverWithState statefulObserver = new ObserverWithState(observer,                    initialState);
        // 添加到集合,如果之前已經添加過了,則return
        ObserverWithState previous = mObserverMap.putIfAbsent(observer,                         statefulObserver);

        ...

        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        //這里的while循環,是實現上圖狀態同步與事件分發的主要邏輯
        //拿觀察者的狀態和宿主當前狀態做比較,如果小于0,說明兩者狀態還沒有對齊。
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            // 將statefulObserver的狀態push進mParentStates列表
            pushParentState(statefulObserver.mState);
            // 接著就會分發一次相應的事件,于此同時statefulObserver的mState對象也會被升級
            // 假設是在宿主的onresume方法內注冊的該觀察者
            // 第一次:分發on_Create事件,觀察者狀態INIT->CREATED 
            // 第二次:分發on_Start事件,觀察者狀態CREATED->STARTED 
            // 第三次:分發on_Resume事件,觀察者狀態STARTED->RESUMED
            statefulObserver.dispatchEvent(lifecycleOwner,                                          upEvent(statefulObserver.mState));
            // 將statefulObserver的狀態從mParentStates列表中移除
            popParentState();
            // 再一次計算觀察者應該到達的狀態,在下一輪循環中和宿主狀態在做比較,知道兩者狀態對齊,退出                // 循環。
            targetState = calculateTargetState(observer);
        }

        ...
    }

    /**
     * 計算目標State
     * 由于要保持“不變性”,被計算的observer的State必要小于等于mObserverMap中最后一個LifecycleObserver的        * State、mState、parentState三者中最小的一個State
     */
private State calculateTargetState(LifecycleObserver observer) {
    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

    State siblingState = previous != null ? previous.getValue().mState : null;
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
        : null;
    return min(min(mState, siblingState), parentState);
}

上面這段代碼則是LifecycleRegistry添加一個觀察者需要做的事。

在理解上述代碼之前,需要有三個觀念:

  • State從INITIALIZED到RESUMED狀態是增大的過程(State這個枚舉類也是按此特定順序排列的)。
  • 存儲觀察者的數據結構,是一個鏈表實現的Map,因為在我們遍歷觀察者列表的時候,觀察者可能隨時被移除。
  • "不變性" -- 先添加的觀察者observer1的狀態state1,永遠要比后添加的觀察者observer2的狀態state2大,即state1 >= state2。(原因:新添加的observer初始State是INITIALIZED,如果當前宿主處于onResume,那么需要將該觀察者的狀態State從INITIALIZED增大為RESUMED,因此mObserverMap中原先已經添加的LifecycleObserver的State肯定>=INITIALIZED)

疑問1:mParentStates這個列表的作用是什么?為什么計算目標State時,需要取觀察者列表中最后一個觀察者的State、宿主當前的State、mParentStates最后一個State中的最小值?

    // we have to keep it for cases:
    // void onStart() {
    //     mRegistry.removeObserver(this);
    //     mRegistry.add(newObserver);
    // }

上面的例子很好地解釋了這個問題,假如我在onStart方法中移除了當前觀察者,而同時我又添加了一個新地觀察者,這時新的觀察者理應從初始狀態被增大至Created狀態,但是由于我們在onStart方法中移除了當前觀察者,我們從mObserverMap中無法找到移除的當前觀察者,則此時則無法保證"不變性"。

疑問2:為什么要將LifecycleObserver封裝成ObserverWithState對象?

static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) {
        // 兼容多種LifecycleObserver
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }

    void dispatchEvent(LifecycleOwner owner, Event event) {
        // 再一次根據需要分發的事件類型反推出該觀察者的狀態
        State newState = getStateAfter(event);
        mState = min(mState, newState);
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

ObserverWithState是一個攜帶著狀態的生命周期觀察者類,其職責僅有一點:

  • 將傳入的LifecycleObserver轉化為LifecycleEventObserver,前面我們提到過觀察者共有三種類型,每種類型接受事件的形式不一樣,需要在分發事件的收口點做一個兼容轉化。

?
lifecycle4

?

5. 生命周期事件Event如何通知到注冊的生命周期觀察者?

? 生命周期事件的分發過程如下:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event){      
        //宿主的每個生命周期的變化都會分發一個對應的Lifecycle.Event,走到這里
        //此時會根據需要分發的事件反推出 宿主當前的狀態
        State next = getStateAfter(event);
        moveToState(next);
    }

private void moveToState(State next) {
        ...
        mState = next;
        sync();
        ...
}

/**
* 判斷所有觀察者是否已經“同步”
* 同步的意思是所有的觀察者都處于相同的狀態
* 由之前說的“不變性”可知,最新的觀察者和最老的觀察者的狀態如果相等,則足以說明已經同步
*/
private boolean isSynced() {
    if (mObserverMap.size() == 0) {
        return true;
    }
    State eldestObserverState = mObserverMap.eldest().getValue().mState;
    State newestObserverState = mObserverMap.newest().getValue().mState;
    return eldestObserverState == newestObserverState && mState ==              newestObserverState;
}

// moveToState方法只是將傳入的宿主新的state和前持有宿主狀態作比對,然后保存一下。
//如果宿主狀態有變動,則調用sync方法來完成事件的分發和觀察者狀態的同步
private void sync() {
        while (!isSynced()) {
        //如果宿主當前轉態 小于 mObserverMap集合中最先添加的那個觀察者的狀態
        //則說明宿主可能發生了狀態回退,比如當前是RESUMED狀態,執行了onPause則回退到STARTED狀態
        //此時調用backwardPass把集合中的每個一觀察者分發一個on_pause事件,并同步它的狀態。
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
        //如果宿主當前轉態 大于 mObserverMap集合中最先添加的那個觀察者的狀態
        //則說明宿主可能發生了狀態前進,比如當前是STARTED狀態,執行了onResume則前進到RESUMED狀態
        //此時調用forwardPass把集合中的每個一觀察者分發一個on_resume事件,并同步它的狀態。
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
    }

LifecycleRegistry在收到handleLifecycleEvent()后,內部調用moveToState()方法,改變State值,每一次State值改變,都會調用LifecycleObserver.onStateChanged()方法將Event分發到LifecycleObserver

其實需要完成的事情很簡單:就是先改變LifecycleRegistry的狀態,然后把狀態“同步”到所有的觀察者,代碼中時刻都在維護著我們前面提到的"不變性",這個規則給我們去判斷是否同步完成的依據。

四. Lifecyle其他的酷炫玩法

  1. 監聽應用前后臺切換:ProcessLifecycleOwner -- Lifecyle的成員之一可以幫助你輕松做到
  2. 自動處理生命周期的Handler:將Handler實現LifecycleObserver接口并給其提供一個需要感知的LifecycleOwner 對象,在接收到ON_DESTROY事件時移除監聽。
  3. 免反注冊事件監聽的事件總線: LiveDataBus, 及其約束進階版
  4. 結合ViewModel & dataBinding, 優雅地實現MVVM架構
  5. 自動處理生命周期的Service:LifecycleService

五. 總結

Lifecycle本質上就是一個觀察者模式的完美詮釋,它成功地解耦了需要監聽生命周期的組件與Activity或Fragment之間的依賴關系,免去了手動管理生命周期的困難,減少了內存泄漏的風險。

擁抱Jetpack,擁抱未來!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。