The overall design

Lifecycle’s core design pattern is the observer pattern.

  • LifeCycleOwner is the observed, and LifecycleObserver is the observer.

  • LifecycleRegistry acts as a mediator, managing the observer and observed, handling events from LifeCycleOwner, synchronizing state, and notifying all LifecycleObservers.

LifeCycle

LifeCycle State and Events

Take a look at some definitions of LifecycleRegistry’s parent class, Lifecycle.

MainThread public Abstract void addObserver(@nonnull LifecycleObserver  observer); @mainThread public abstract void removeObserver(@nonnull LifecycleObserver Observer); @mainThread @nonNULL public Abstract State getCurrentState(); Public enum Event {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY} public enum State {DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; }}}Copy the code
  • Pay attention toAddObserver, removeObserver, getCurrentStateAll of these methods have been added@MainThreadNotes, so in the process of use, try to putCall from the main threadOtherwise it may cause some crash problems. (multithreaded collection operation, may cause ArrayIndexOutOfBoundsException)
  • Event-driven:LifecycleRegistrythroughhandleLifecycleEventMethod to receive external messagesEventEvent to modify internalStateStatus and notification to allLifecycleObserver.

State transition

Take a look at the diagram of State and Event, and then take a look at the code.

  1. Using the getStateAfter method, you can obtain the next State value based on the Event.
  2. Going from left to right is called state going up.
  3. Going from right to left is called state descent.
  4. UpEvent: Gets the next Event based on the state of the current observer.
    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);
    }

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

    private static Event upEvent(State state) {
        switch (state) {
            case INITIALIZED:
            case DESTROYED:
                return ON_CREATE;
            case CREATED:
                return ON_START;
            case STARTED:
                return ON_RESUME;
            case RESUMED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }
Copy the code

State the size

Because State is an enumeration type, and the compareTo method of an enumeration type compares the ordinal value of each enumeration, the State size is: DESTROYED < INITIALIZED < CREATED < STARTED < RESUMED.

Examples of scenarios used:

LiveData#observe, which updates only active owner objects by default. (Here is not much analysis of LiveData source, only a small part of the logic)

public void observe(@NonNull LifecycleOwner owner,Observer<? Super T > observer);Copy the code
  1. LiveData, will callconsiderNotifyThe appropriate observer will be notified.
  2. useshouldBeActive()Check the lifecycle status of the current owner. If the owner corresponding to the current Observer is inactive, return.
  3. LifecycleBoundObserverShouldBeActive, say the current State is at least State.STARTED.
  4. This explains that when the Activity is in the background and the corresponding State is state. STARTED, it will not receive LiveData events.
//LiveData private void considerNotify(ObserverWrapper observer) { if (! observer.mActive) { return; } // if (! observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); } //LifecycleBoundObserver class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver);  return; } activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); }}Copy the code

LifecycleRegistry

LifecycleRegistry acts as a mediator, managing the observer and observed, and handling event distribution and state transitions.

Bind the observed

  • Pass in by constructorLifecycleOwnerThat is, the observed. In most cases, the corresponding is an Activity or Fragment.
  • throughMLifecycleOwner weak referencesThe Activity and fragments. This facilitates garbage collection and also prevents the corresponding component from being further leaked if LifeCycleRegistry leaks.
  • Ok, this step is easy. In this case, LifecycleRegistry holds the observed.
    private final WeakReference<LifecycleOwner> mLifecycleOwner;

    public LifecycleRegistry(@NonNull LifecycleOwner,也就是被观察者。一般情况下, 指的就是Activity或者Fragment。
    provider) {
        mLifecycleOwner = new WeakReference<>(provider);
        mState = INITIALIZED;
    }
Copy the code

Add observer

LifecycleRegistry#addObserver

FastSafeIterableMap
  • All observers will eventually be saved to onemObserverMapIn the set of
  • FastSafeIterableMapIt’s essentially oneBidirectional linked list +HashMapThe structure of the. (One more HashMap, space for time, improve query efficiency, solve the problem of low efficiency of linked list traversal query)
  • Map.EntryStructure, which contains references to the front and back nodes, and its own key and value values.

private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>(); public void addObserver(@NonNull LifecycleObserver observer) { ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); if (previous ! = null) { return; } // omit code}Copy the code
ObserverWithState
static class ObserverWithState { State mState; LifecycleEventObserver mLifecycleObserver; ObserverWithState(LifecycleObserver observer, State initialState) { 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; }}Copy the code
  • ObserverWithState, wrapped in the original LifecycleEvening Server (that is, the parameters in addObserver), throughdispatchEvent()Notifies the Observer of a status changeonStateChangedMethods.
  • mStateFields,Save the state of the current LifecycleObserver. Why do YOU need this field?
  1. Because the state of LifeCycleRegistry is not necessarily the same as the state of LifecycleObserver, you need to constantly synchronize the state of LifeCycleRegistry to each LifecycleObserver.
  2. State synchronization is a step by step processInstead of changing the value of state directly at once, you can use dispatchEvent to send events step by step.
  3. INITIALIZED to State. The mState of the LifecycleObserver becomes state.created, STARTED, and state.resume. (The same goes for the state descent.)
example

Example scenario: Add a new LifecycleObserver during the Activity onResume. Output: The newly added LifecycleEventObserver, onStateChanged will receive event.on_CREATE, Event.on_start, event.on_resume events in order.

@Override protected void onResume() { super.onResume(); getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner Log.d(TAG, "onStateChanged, Event :"+ Event); }}); } // Logs onStateChanged, event:ON_CREATE onStateChanged, event:ON_START onStateChanged, event:ON_RESUMECopy the code

Analysis process:

  1. For this new addition to Life Dinner Server, startObserverWithStateThe inside of themStateThe value isINITIALIZED, but LifecycleRegistry is now RESUME State.
  2. throughcalculateTargetStateThe mState in ObserverWithState should also be changed to RESUME.
  3. Call it through a White loopdispatchEventThe ON_CREATE, ON_START, and ON_RESUME methods are distributed toObserverWithState#mLifecycleObserverChange the mState in ObserverWithState until it matches the State of LifecycleRegistry.
  4. And that’s actually how the state goes up.

Event distribution and status synchronization

LifeCycleOwner distributes lifecycle events to LifeCycleRegistry by calling the handleLifecycleEvent method. LifeCycleRegistry synchronizes the state based on the event and notifies all observers.

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) { State next = getStateAfter(event); moveToState(next); } private void moveToState(State next) { if (mState == next) { return; } mState = next; if (mHandlingEvent || mAddingObserverCounter ! = 0) { mNewEventOccurred = true; return; } mHandlingEvent = true; sync(); mHandlingEvent = false; } private void sync() { while (! isSynced()) { mNewEventOccurred = false; // State drops if (mState.compareTo(mobServermap.eldest ().getValue().mstate) < 0) {backwardPass(lifecycleOwner); } // Status rise Entry<LifecycleObserver, ObserverWithState> newest = mobServermap.newest (); if (! mNewEventOccurred && newest ! = null && mState.compareTo(newest.getValue().mState) > 0) { forwardPass(lifecycleOwner); } } mNewEventOccurred = false; } 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; } private void forwardPass(LifecycleOwner lifecycleOwner) { Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator = mObserverMap.iteratorWithAdditions(); while (ascendingIterator.hasNext() && ! mNewEventOccurred) { Map.Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next(); ObserverWithState observer = entry.getValue(); while ((observer.mState.compareTo(mState) < 0 && ! mNewEventOccurred && mObserverMap.contains(entry.getKey()))) { pushParentState(observer.mState); final Event event = Event.upFrom(observer.mState); if (event == null) { throw new IllegalStateException("no event up from " + observer.mState); } observer.dispatchEvent(lifecycleOwner, event); popParentState(); }}}Copy the code
  1. getStateAfter(): Based on Event, get the next State value (i.e. the State transition logic above)
  2. moveToState(): Moves to the current State.
  3. sync(): Synchronizes status, updating the status of all observers in the queue and calling the status of all observersonStateChanged.
  4. isSynced(): Check whether State synchronization is complete: If the State of the queue header and queue tail is the same as that of LifecycleRegistry, the State synchronization process is complete.
  5. backwardPass(): A process of state degradation. (From right to left)
  6. forwardPass(): a process of state ascent. (From left to right)

The forwardPass method implements the first while loop that iterates through all observers in the queue. The second while loop, which steps up the mState of each Observer and calls dispatchEvent for notification, directly matches the State of LifecycleRegistry.

LifeCycleOwner

LifecycleOwner: The observed, holds the Lifecycle object. Both activities and fragments implement LifecycleOwner, indicating that they are components with a lifecycle.

Lifecycle event distribution implementation

  • Distribution of Activity lifecycle events is done through aReportFragmentFor processing.ReportFragment is a fragment without a UI.
  • inComponentActivity#onCreateThe time,Injection adds a ReportFragment. Because a Fragment depends on the Activity that created it, the Fragment’s life cycle synchronizes with that of the host Activity, thus indirectly monitoring the Activity’s life cycle.
  • In the corresponding ReportFragment lifecycle method, passReportFragment#dispatchMethod to distribute Activity lifecycle events toLifecycleRegistry.
  • LifecycleRegistry does state synchronization and notifies all observers.

LifecyclerObserver

An observer can listen for lifecycle changes corresponding to LifecycleOnwer. I won’t go into details. So let’s talk about some of the things that you might want to pay attention to in practice.

AddObserver wants to put the main thread

Private ArrayList<State> mParentStates = new ArrayList<>(); public void addObserver(@NonNull LifecycleObserver observer) { State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED; ObserverWithState statefulObserver = new ObserverWithState(observer, initialState); ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); if (previous ! = null) { return; } State targetState = calculateTargetState(observer); while ((statefulObserver.mState.compareTo(targetState) < 0 && mObserverMap.contains(observer))) { pushParentState(statefulObserver.mState); statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState)); popParentState(); // mState / subling may have been changed recalculate targetState = calculateTargetState(observer); } } 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); }Copy the code
  1. AddObserver adds observers, and there is a state synchronization process. MParentStates.
  2. mParentStates: This is a passpopParentStateandpushParentStateUpdate the stack. During state synchronization, pushParentState is pushed before executing the subscriber’s dispatchEvent callback, and popParentState is pushed out after the callback
  3. MParentStates is aArrayList.ArrayList is not thread-safe
  4. So if multiple threads are executing the addObserver process at the same time, it may cause a crash.

Check whether addObserver is in the main thread

Take Activity as an example.

  1. Projects typically have a BaseActivity class that you can override directly from BaseActivitygetLifecycleMethod returns a new oneLifecycleRegistryWill do.
  2. With this new LifecycleRegistry, you can override the addObserver method to intercept all observers that listen to the Activity lifecycle.
  3. Checks whether the current thread is the main thread. If it is not on the main thread, you can print the relevant stack information to prompt the developer to make changes
abstract class BaseActivity : Appactivity () {// In the compatactivity () stage of local development, if you are on a non-mainline program addObserver, just type an error log or throw exception to prompt the developer to change var customLifeCycle: CustomLifeCycle? = null override fun getLifecycle(): Lifecycle? { if (DEBUG) { if (customLifeCycle == null) { customLifeCycle = CustomLifeCycle(this) } return customLifeCycle } return super.getLifecycle() } } class CustomLifeCycle extends LifecycleRegistry { public CustomLifeCycle(@NonNull LifecycleOwner provider) { super(provider); } @override public void addObserver(@nonnull LifecycleObserver observer) {if (looper.getMainLooper ()! = Looper.myLooper()){ throw new IllegalStateException("addObserver need in main thread"); } super.addObserver(observer); }}Copy the code