【AAC 系列二】深入理解架構元件的基石:Lifecycle

程式亦非猿發表於2019-05-13

0. 序言

你好,我是程式亦非猿,阿里巴巴資深客戶端工程師一枚

本文是深入理解 AAC 系列的第二篇,第一篇請看這裡:juejin.im/post/5cd4ea…

在前文,我就提到 Android Architecture Components (後簡稱為 AAC),是一個幫助開發者設計 健壯 、 可測試 且 可維護 的一系列庫的集合。

Lifecycle  就是 AAC 中的一員,它能夠幫助我們方便的管理 Activity 以及 Fragment 的生命週期

本文帶大家深入瞭解 Lifecycle 。

注意:本文基於 Lifecycle 1.1.1 版本,Android API 26 ,依賴如下圖。

image.png



並假設讀者對 Lifecycle 有基本的瞭解,我繪製了一個基本的類圖,如果對於下面類圖所涉及到的類都還算了解則可以繼續閱讀下去,如果完全不知道,建議閱讀一些教程先。

image.png

1. Lifecycle 使用基礎

在 AppCompatActivity 裡我們可以通過 getLifecycle() 方法拿到 Lifecycle ,並新增 Observer 來實現對 Activity 生命週期的監聽。

一個簡單的使用例子如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testLifecycle();
    }

    private void testLifecycle() {
        getLifecycle().addObserver(new LifecycleObserver() {

            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
            void onResume(){
                Log.d(TAG, "LifecycleObserver onResume() called");
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: ");
    }
}
複製程式碼

啟動 MainActivity 就可以看到如下日誌:

D/MainActivity: onResume: 
D/MainActivity: LifecycleObserver onResume() called
複製程式碼

日誌說明我們通過上述程式碼確實實現了監聽生命週期的功能。

那麼問題來了,這是怎麼做到的?

我把這個問題拆分成了兩塊:

  1. 生命週期的感知問題是什麼感知了Activity的生命週期 ?
  2. 註解方法的呼叫問題是什麼呼叫了我們使用註解修飾的方法 ?

2. 感知生命週期的原理

2.1 初現端倪 ReportFragment

我通過除錯堆疊發現了一個叫做 ReportFragment  的類,非常可疑,遂跟蹤之。

注意:Debug 檢視堆疊是閱讀原始碼手段中最常用最簡單最好用最親民的方法,沒有之一,每個人都應該熟練掌握。

來看看這個類都寫了什麼:

public class ReportFragment extends Fragment {

    private static final String REPORT_FRAGMENT_TAG = "android.arch.lifecycle"
            + ".LifecycleDispatcher.report_fragment_tag";
		//注入 Fragment 的方法
    public static void injectIfNeededIn(Activity activity) {
        // ProcessLifecycleOwner should always correctly work and some activities may not extend
        // FragmentActivity from support lib, so we use framework fragments for activities
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            // Hopefully, we are the first to make a transaction.
            manager.executePendingTransactions();
        }
    }
    //...
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

    @Override
    public void onStart() {
        super.onStart();
        dispatchStart(mProcessListener);
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatchResume(mProcessListener);
        dispatch(Lifecycle.Event.ON_RESUME);
    }

    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }

    @Override
    public void onStop() {
        super.onStop();
        dispatch(Lifecycle.Event.ON_STOP);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
        // just want to be sure that we won't leak reference to an activity
        mProcessListener = null;
    }
		//分發生命週期事件給 LifecycleRegistryOwner 的 Lifecycle 或者 LifecycleRegistry
    private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }
   //...
}
複製程式碼

一看程式碼我們就知道了,它重寫了生命週期回撥的方法,確實是這個 ReportFragment 在發揮作用,Lifecycle 利用了 Fragment 來實現監聽生命週期,並在生命週期回撥裡呼叫了內部 dispatch  的方法來分發生命週期事件。(怎麼分發後面講)

2.2 幕後“黑手” SupportActivity

從方法來看注入 Fragment 的方法應該是呼叫 injectIfNeededIn(Activity)  的地方了。

在通過搜尋 發現 SupportActivity  呼叫了該方法。(API 28 的版本是 ComponentActivity ,程式碼實現沒什麼差別)

public class SupportActivity extends Activity implements LifecycleOwner, Component {

    //擁有一個 LifecycleRegistry
    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      	//在 onCreate 裡注入了 ReportFragment
        ReportFragment.injectIfNeededIn(this);
    }

    @CallSuper
    protected void onSaveInstanceState(Bundle outState) {
        this.mLifecycleRegistry.markState(State.CREATED);
        super.onSaveInstanceState(outState);
    }

    public Lifecycle getLifecycle() {
        return this.mLifecycleRegistry;
    }
}
複製程式碼

可以看到 SupportActivity 內部包含了一個 LifecycleRegistry ,並實現了 LifecycleOwner  , 並且在 onCreate 方法裡 呼叫了 ReportFragment.injectIfNeededIn(this); 注入ReportFragment  。

LifecycleRegistry  是 Lifecycle 的實現,並負責管理 Observer ,在上面【2】章節的 dispatch  方法中已經看到了該類的出現,它的 handleLifecycEvent  接受了生命週期的回撥。

2.3 Lifecycle 的生命週期事件與狀態的定義

這小節補充一下 Lifecycle  的回撥與 Activity 、Fragment 的生命週期對標相關知識,後面分析會出現。

Lifecycle  中定義了 Event : 表示生命週期事件, State : 表示當前狀態。

2.3.1 Lifecycle.Event

Lifecycle  定義的生命週期事件,與 Activity 生命週期類似。

    public enum Event {
        ON_CREATE,
        ON_START,
        ON_RESUME,
        ON_PAUSE,
        ON_STOP,
        ON_DESTROY,
        ON_ANY
    }
複製程式碼

2.3.2 Lifecycle.State

State  表示當前元件的生命週期狀態。

    /**
 		* Lifecycle states. You can consider the states as the nodes in a graph and
 		* {@link Event}s as the edges between these nodes.
 		*/
		public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
複製程式碼

2.3.3 Event 與 State 的關係:

image.png

(圖1.圖來源見【8.2】)

2.4 小結

通過研究我們發現,SupportActivity 在 onCreate 方法裡注入了 ReportFragment ,通過 Fragment 的機制來實現生命週期的監聽

實際上利用 Fragment 監聽 Activity 生命週期的功能在開源社群由來已久, Lifecycle 並非原創,Lifecycle 的出現算是把這個實現官方化了。

相比於第三方的實現,嵌入到 Android 原始碼中的實現對開發者來說是非常有好處的,即遮蔽了細節,又降低了使用難度。
**

3. 註解方法被呼叫的原理

OnLifecycleEvent  註解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnLifecycleEvent {
    Lifecycle.Event value();
}
複製程式碼

看到有 RetentionPolicy.RUNTIME 修飾,我就猜測它是靠反射來實現了,不過還是看下具體實現驗證下吧。

之前在瞭解完生命週期監聽的原理的同時,我們也看到了生命週期事件的接收者 LifecycleRegistry ,是它的 handleLifecycleEvent()   接收了事件,我們繼續追蹤。

    /**
     * Sets the current state and notifies the observers.
     * Note that if the {@code currentState} is the same state as the last call to this method,
     * calling this method has no effect.
     */
    public void handleLifecycleEvent(Lifecycle.Event event) {
        mState = getStateAfter(event);
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }
複製程式碼

其實從方法註釋就能看出來了,就是它處理了狀態並通知了 observer 。

看下 getStateAfter()  方法:

   static State getStateAfter(Event event) {
        switch (event) {
            case ON_CREATE:
            case ON_STOP:
                return CREATED;
            case ON_START:
            case ON_PAUSE:
                return STARTED;
            case ON_RESUME:
                return RESUMED;
            case ON_DESTROY:
                return DESTROYED;
            case ON_ANY:
                break;
        }
        throw new IllegalArgumentException("Unexpected event value " + event);
    }
複製程式碼

getStateAfter()  這個方法根據當前 Event 獲取對應的 State  ,細看其實就是 【2.3.3】中那個圖的程式碼實現。

接下去看 sync()  方法:

    private void sync() {
        while (!isSynced()) {
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass();
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass();
            }
        }
        mNewEventOccurred = false;
    }
複製程式碼

sync 方法裡對比了當前 mState 以及上一個 State ,看是應該前移還是後退,這個對應了生命週期的前進跟後退,打個比方就是從 onResume -> onPause (forwardPass),onPause -> onResume (backwardPass),拿 backwardPass() 舉例吧。(forwardPass方法處理類似)

    private void backwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
                mObserverMap.descendingIterator();
        while (descendingIterator.hasNext() && !mNewEventOccurred) {
            Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
            ObserverWithState observer = entry.getValue();
            while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                //呼叫 downEvent 獲取更前面的 Event
                Event event = downEvent(observer.mState);
                pushParentState(getStateAfter(event));
                //分發 Event 
                observer.dispatchEvent(lifecycleOwner, event);
                popParentState();
            }
        }
    }
		
    private static Event downEvent(State state) {
        switch (state) {
            case INITIALIZED:
                throw new IllegalArgumentException();
            case CREATED:
                return ON_DESTROY;
            case STARTED:
                return ON_STOP;
            case RESUMED:
                return ON_PAUSE;
            case DESTROYED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }
複製程式碼

通過原始碼可以看到, backwardPass()  方法呼叫 downEvent  獲取往回退的目標 Event。

可能比較抽象,舉個例子,在 onResume 的狀態,我們按了 home,這個時候就是 RESUMED 的狀態變到 STARTED 的狀態,對應的要傳送的 Event 是 ON_PAUSE,這個就是 backwardPass() 的邏輯了

如果前面的程式碼都是引子的話,我們最終看到了一絲分發的痕跡了—— observer.dispatchEvent(lifecycleOwner, event) 。

    static class ObserverWithState {
        State mState;
        GenericLifecycleObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            //這裡
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }
複製程式碼

可以看到最後呼叫了 GenericLifecycleObserver.onStateChanged() 方法,再跟。

class ReflectiveGenericLifecycleObserver implements GenericLifecycleObserver {
    //mWrapped 是 我們的 Observer
    private final Object mWrapped;
    //反射 mWrapped 獲取被註解了的方法
    private final CallbackInfo mInfo;
    @SuppressWarnings("WeakerAccess")
    static final Map<Class, CallbackInfo> sInfoCache = new HashMap<>();

    ReflectiveGenericLifecycleObserver(Object wrapped) {
        mWrapped = wrapped;
        mInfo = getInfo(mWrapped.getClass());
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Event event) {
        invokeCallbacks(mInfo, source, event);
    }
    
    private void invokeCallbacks(CallbackInfo info, LifecycleOwner source, Event event) {
        invokeMethodsForEvent(info.mEventToHandlers.get(event), source, event);
        invokeMethodsForEvent(info.mEventToHandlers.get(Event.ON_ANY), source, event);
    }
  
    private void invokeMethodsForEvent(List<MethodReference> handlers, LifecycleOwner source,
            Event event) {
        if (handlers != null) {
            for (int i = handlers.size() - 1; i >= 0; i--) {
                MethodReference reference = handlers.get(i);
                invokeCallback(reference, source, event);
            }
        }
    }
    //最後走到 invokeCallback 這裡
    private void invokeCallback(MethodReference reference, LifecycleOwner source, Event event) {
        //noinspection TryWithIdenticalCatches
        try {
            switch (reference.mCallType) {
                case CALL_TYPE_NO_ARG:
                    reference.mMethod.invoke(mWrapped);
                    break;
                case CALL_TYPE_PROVIDER:
                    reference.mMethod.invoke(mWrapped, source);
                    break;
                case CALL_TYPE_PROVIDER_WITH_EVENT:
                    reference.mMethod.invoke(mWrapped, source, event);
                    break;
            }
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Failed to call observer method", e.getCause());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
	
    private static CallbackInfo getInfo(Class klass) {
        CallbackInfo existing = sInfoCache.get(klass);
        if (existing != null) {
            return existing;
        }
        existing = createInfo(klass);
        return existing;
    }
    
    //通過反射獲取 method 資訊
    private static CallbackInfo createInfo(Class klass) {
        //...
        Method[] methods = klass.getDeclaredMethods();

        Class[] interfaces = klass.getInterfaces();
        for (Class intrfc : interfaces) {
            for (Entry<MethodReference, Event> entry : getInfo(intrfc).mHandlerToEvent.entrySet()) {
                verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass);
            }
        }

        for (Method method : methods) {
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
            if (annotation == null) {
                continue;
            }
            Class<?>[] params = method.getParameterTypes();
            int callType = CALL_TYPE_NO_ARG;
            if (params.length > 0) {
                callType = CALL_TYPE_PROVIDER;
                if (!params[0].isAssignableFrom(LifecycleOwner.class)) {
                    throw new IllegalArgumentException(
                            "invalid parameter type. Must be one and instanceof LifecycleOwner");
                }
            }
            Event event = annotation.value();
            //...
            MethodReference methodReference = new MethodReference(callType, method);
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
        }
        CallbackInfo info = new CallbackInfo(handlerToEvent);
        sInfoCache.put(klass, info);
        return info;
    }

    @SuppressWarnings("WeakerAccess")
    static class CallbackInfo {
        final Map<Event, List<MethodReference>> mEventToHandlers;
        final Map<MethodReference, Event> mHandlerToEvent;

        CallbackInfo(Map<MethodReference, Event> handlerToEvent) {
            //...
        }
    }

    static class MethodReference {
        final int mCallType;
        final Method mMethod;

        MethodReference(int callType, Method method) {
            mCallType = callType;
            mMethod = method;
            mMethod.setAccessible(true);
        }
    }

    private static final int CALL_TYPE_NO_ARG = 0;
    private static final int CALL_TYPE_PROVIDER = 1;
    private static final int CALL_TYPE_PROVIDER_WITH_EVENT = 2;
}
複製程式碼

這個類的程式碼比較多,不過也不復雜。可以看到最後程式碼走到了invokeCallback() ,通過反射呼叫了方法。

而這個方法是 createInfo() 方法中反射遍歷我們註冊的 Observer 的方法找到的被 OnLifecycleEvent 註解修飾的方法,並且按 Event 型別儲存到了 info.mEventToHandlers 裡。

到這裡整個鏈路就清晰了,我們在 Observer 用註解修飾的方法,會被通過反射的方式獲取,並儲存下來,然後在生命週期發生改變的時候再找到對應 Event 的方法,通過反射來呼叫方法

**注意:**原始碼中還有一些細節比較繁瑣,比如怎麼獲取的方法,怎麼包裝的 Observer ,State 的管理以及儲存等,就不在這裡展開了,有興趣的自行了解。

4. 圖解 Lifecycle

如果被程式碼繞暈了,也沒關係,我畫了類圖以及時序圖,幫助大家理解,配合著類圖跟時序圖看程式碼,會容易理解很多。

4.1 Lifecycle 相關原理類的 UML 圖

核心類 UML 圖整理如下:

Lifecycle-UML.jpg

(圖2. Lifecycle-UML圖)

4.1 Lifecycle 原理時序圖

圖中起始於 onCreate ,順便利用 onCreate 描繪整個流程。(其他生命週期原理一樣,不重複畫了)

image.png

(圖3. Lifecycle 時序圖)

4.3 Lifecycle State 與 Event 的關係圖

圖展示了 State 與 Event 的關係,以及隨著生命週期走向它們發生的變化。

Lifecycle-Seq2.png

(圖4. State 與 Event 的關係圖)

5. Lifecycle 的實戰應用

好了,重點的原理我們分析完畢了,如果看一遍沒有理解,就多看幾遍。

這個小節來講講 Lifecycle 的實戰應用。

Lifecycle 的應用場景非常廣泛,我們可以利用 Lifecycle 的機制來幫助我們將一切跟生命週期有關的業務邏輯全都剝離出去,進行完全解耦,比如視訊的暫停與播放,Handler 的訊息移除,網路請求的取消操作,Presenter 的 attach&detach View 等等,並且可以以一個更加優雅的方式實現,還我們一個更加乾淨可讀的 Activity & Fragment。

下面舉個簡單的例子:

5.1 自動移除 Handler 的訊息:LifecycleHandler

我們擔心 Handler 會導致記憶體洩露,通常會在 onDestroy 裡移除訊息,寫多了煩,但是結合 Lifecyc le ,我們可以寫出一個 lifecycle-aware 的 Handler,自動在 onDestroy 裡移除訊息,不再需要寫那行樣板程式碼。

程式碼實現如下:

image.png

該程式碼已經包含在我的開源庫 Pandora 裡了,可以訪問:github.com/AlanCheen/P… ,直接依賴使用,歡迎 star。

5.2 給 ViewHolder 新增 Lifecycle 的能力

有些 App 會有長列表的頁面,裡面塞了各種不用樣式的 Item,通常會用 RecyclerView 來實現,有時候部分 Item 需要獲知生命週期事件,比如包含播放器的 Item 需要感知生命週期來實現暫停/重播的功能,藉助 Lifecycle 我們可以實現。

具體實現可以參考我的開源庫 Flap:github.com/AlanCheen/F… 。

6. 知識點梳理彙總

  1. **Lifecycle**  庫通過在 SupportActivity  的 onCreate  中注入 ReportFragment  來感知發生命週期;
  2. **Lifecycle**  抽象類,是 Lifecycle  庫的核心類之一,它是對生命週期的抽象,定義了生命週期事件以及狀態,通過它我們可以獲取當前的生命週期狀態,同時它也奠定了觀察者模式的基調;(我是黨員你看出來了嗎:-D)
  3. **LifecycleOwner**  ,描述了一個擁有生命週期的元件,可以自己定義,不過通常我們不需要,直接使用 AppCompatActivity  等即可;
  4. **LifecycleRegistry**  是 Lifecycle  的實現類,它負責接管生命週期事件,同時也負責 Observer  的註冊以及通知;
  5. **ObserverWithState** ,是 Observer 的一個封裝類,是它最終 通過 ReflectiveGenericLifecycleObserve 呼叫了我們用註解修飾的方法;
  6. **LifecycleObserver** ,Lifecycle 的觀察者,利用它我們可以享受 Lifecycle 帶來的能力;
  7. **ReflectiveGenericLifecycleObserver**,它儲存了我們在 Observer 裡註解的方法,並在生命週期發生改變的時候最終通過反射的方式呼叫對應的方法。

7. 總結

Lifecycle 是一個專門用來處理生命週期的庫,它能夠幫助我們將 Acitivity、Framgent 的生命週期處理與業務邏輯處理進行完全解耦,讓我們能夠更加專注於業務;通過解耦讓 Activity、Fragment 的程式碼更加可讀可維護。

可以這麼說 Lifecycle 的出現徹底解決了 Android 開發遇到的生命週期處理難題,並且還給開發者帶來了新的架構姿勢,讓我們可以設計出更加合理的架構。

媽媽再也不用擔心我遇到生命週期難題了!

同時 Lifecycle 作為 AAC 的基石,為 LiveDataViewModel 的登場打下堅實的基礎。

那麼,LiveData、ViewModel 的背後又是什麼原理呢?

盡請期待下一篇!

8. 參考與推薦

  1. developer.android.com/topic/libra…
  2. developer.android.com/topic/libra…

公眾號:程式亦非猿

相關文章