• Lifecycle (I) origins of Android Jetpack architectural components
  • Lifecycle (ii) for Android Jetpack architecture components
  • Lifecycle (iii) of Android Jetpack architectural components

Lifecycle implementation principle analysis


All source code is based on the latest version of Lifecycle v2.2.0


Lifecycle’s source code is light and lightweight.

Lifecycle’s core design pattern is the observer pattern, which can also be seen through Lifecycle’s approach: addObserver(LifecycleObserver Observer).

One of the interesting things Lifecycle will look at is how the timing of an Activity’s Lifecycle changes is implemented.

Assuming we haven’t seen the source code yet, here’s a guess:

When LifecycleOwner’s method addObserver() is called, it’s easy to think that Lifecycle uses a data structure to store the observer, and then when the Activity’s Lifecycle changes, Lifecycle iterates through this observers collection, calling each observer’s callback method, in which we write our own code. This is easy to think about, but not easy to think about is how Lifecycle accurately timing changes in the Lifecycle

The answer can only be found in the source code

Lifecycle’s source code is roughly divided into two parts:

  • addObserver()Register an observer for the view controller
  • Listen for life cycle changes and notify the observer

The registration process

To register an observer, call getLifecycle().addobServer (LifecycleObserver Observer) in the view controller.

View controllers: Activity and Fragment both implement LifecycleOwner, marking them as components with Lifecylce. First look at getLifecycle() in LifecycleOwner:

public Lifecycle getLifecycle(a)
Copy the code

The return type of this method is Lifecycle. Lifecycle is an abstract class:

public abstract class Lifecycle {

    AtomicReference<Object> mInternalScopeRef = new AtomicReference<>();
   
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);
    @MainThread
    public abstract State getCurrentState(a);

    @SuppressWarnings("WeakerAccess")
    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

Lifecycle has three methods and two enumerations. Two enumerations define two core concepts in the Lifecycle Lifecycle: events and states, as described in detail in Lifecycle (2) of the Android Jetpack architecture component. Three methods: Add observer, remove observer, query current status. It also illustrates the major functionality of the Lifecycle class

  • Add an observer observer, parse the observer, store it in the collection, and remove the observer when appropriate
  • Gets the state of the current LifecycleOwner and is responsible for transitioning between the state and events

Lifecycle is an abstract class and the only concrete implementation class is LifecycleRegistry.

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner.ViewModelStoreOwner.{


    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        / / important
        ReportFragment.injectIfNeededIn(this);
        if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}public Lifecycle getLifecycle(a) {
        returnmLifecycleRegistry; }}Copy the code

You can see that LifecycleOwner’s method getLifecycle returns exactly LifecycleRegistry in Acitivity.

Start with a few member variables in the LifecycleRegistry class:

public class LifecycleRegistry extends Lifecycle {
	/** * Current state */
    private State mState;
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
    private final WeakReference<LifecycleOwner> mLifecycleOwner;
    private int mAddingObserverCounter = 0;
    private boolean mHandlingEvent = false;
}
Copy the code
  • FastSafeIterableMap LifecycleRegistryStores the collection type of the Observer, which functions through a proxyHashMapTo expand. Similar to theLinkedHashMap, set elements ordered, through the linked list will each oneEntryTogether. Supports iteration and add and delete operations simultaneously
  • mLifecycleOwnerWeak references are used here. If theFragmnetorActivitylifecycleA weak reference is protected from leaking the wholeFramgnetActivity(But we’d better not let that happen in developmentlifecycleThe references are exposed)
  • mAddingObserverCountermHandlingEventTwo bool values associated with synchronization operations.
  • mStatesaidLifecycleOwnerThe current state of. whenlifecycleTo detectActivity/FramgnetWhen the life cycle of themStateValue, and then callsync()This method will be otherlifecycleThe data andobserversFor data synchronization, and according tomStateChange distributionmStateThe correspondingEvent.

We then analyze the registration process

The addObserver(LifecycleObserver Observer) method is the entry point to the registration process.

	@Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        LifecycleObserver is converted to LifecycleEventObserver.
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
		// Repeat add, return directly
        if(previous ! =null) {
            return;
        }
        / / found empty
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            return;
        }

		// Whether to reenter
        booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        / / important
        // The initial value of stateFulobServer. mState is
        // INITIALIZED, by comparing with the calculated targetState,
        // If less than, it enters the loop.
        // (DESTROYED is the smallest, INITIALIZED is greater, CREATED is greater, and so on)
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
         	// Save its own state
            pushParentState(statefulObserver.mState);
            / / distribution of the Event
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            // Delete the state
            popParentState();
            // Recalculate the state for loop exit conditions until the observer state progresses from the INITIALIZED state to the current LifecyleOwner state
            targetState = calculateTargetState(observer);
        }
        
		// There is no need to synchronize every time if you reenter, wasting resources, just synchronize once after the last processing of all tasks
        if(! isReentrance) {// Update some properties and distribute events
            sync();
        }
        mAddingObserverCounter--;
    }
Copy the code

This method starts with the first few lines of code: wrap state and observer as ObserverWithState, INITIALIZED as INITIALIZED, stored in the collection, and returned if the observer already exists. When the added observer is a new one, follow the following process.

The isReentrance Boolean means reentry or not; the isReentrance Boolean means reentry or not;

The process of adding addObserver() is executed at the same time or other Event events are being distributed at the same time.

The synchronization method sync() at the end of the method would not be executed if it were reentrant, because it would be redundant to synchronize every state change during reentrant, just the last one.

Remember the example I gave at the end of the last article? Observe the Activity’s ONSTART event and ONCREATE event in an Observer, and only call addObserver() in the Activity’s onResume(). As a result, the Observer can still be notified of events in the nCreate and onStart life cycles

Lifecycle can do this magic and the logic is in this while loop.

For convenience, the analysis of the while loop is written in comments to the code.

Look at the two methods that are involved in this loop dispatchEvent() and upEvent()

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);
            	// Observer callback functionmLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code

You can see that dispatchEvent() actually calls the observer’s callback method, where the logic you wrote is executed, and then updates the mState, which is the observer’s State. You can then work with the upEvent() method

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

And the code comments above should make it easy for you to understand: The observer’s mState is INITIALIZED, and events are continuously distributed forward through upEvent to update the state until the Observer’s mState reaches the mState of the current LifecycleOwner

A complete addObserver() process is complete

LifecycleRegistry as a whole works pretty much as you guessed, so here’s a review

  • Add an observer observer, parse the observer, store it in the collection, and remove the observer when appropriate
  • Gets the state of the current LifecycleOwner and is responsible for transitioning between the state and events

At the end of the registration process, I actually missed out on how Lifecycle will transform the many different LifecycleObserver implementation classes into a unified LifecycleEventObserver implementation class.

Since it doesn’t have much impact on the main line, I won’t expand on it here. If you are interested, you can read the source code for yourself. The entry is in the addObserver() method, which I have commented out

The notification process

Lifecycle holds all observer references once the registration process is complete, so Lifecycle can be implemented by notifying them all about observers when the Activity \Fragment Lifecycle changes. How does Lifecycle perceive changes in the Activity \Fragment Lifecycle?

There’s actually a weird thing about the ComponentActivity class:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner.ViewModelStoreOwner.{...private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); ./ / here
        ReportFragment.injectIfNeededIn(this);
        if(mContentLayoutId ! =0) { setContentView(mContentLayoutId); }}... }Copy the code

Follow along to see what the ReportFragment class does:

public class ReportFragment extends Fragment {
    

    public static void injectIfNeededIn(Activity activity) {
        // Create a Fragment for @param Activity without a UI
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}...@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        dispatch(Lifecycle.Event.ON_CREATE);
    }

    @Override
    public void onStart(a) {
        dispatch(Lifecycle.Event.ON_START);
    }

    @Override
    public void onResume(a) {
        dispatch(Lifecycle.Event.ON_RESUME);
    }

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

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

    @Override
    public void onDestroy(a) {
        dispatch(Lifecycle.Event.ON_DESTROY);
    }

    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 instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}Copy the code

After reading here, I suddenly see. By injecting an Activity with a ReportFragment without a UI, and then writing the Dispathch () method in each ReportFragment lifecycle callback that corresponds to the Activity ** dispatches changes to the lifecycle state. Because a Fragment depends on the Activity that created it, the Fragment’s Lifecycle is synchronized with the Activity’s Lifecycle, thus indirectly implementing the ability for Lifecycle to listen to the Activity’s Lifecycle. Then look at how events are distributed by dispatch() :

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 instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}Copy the code

LifecycleOwner is forced upward after calling getActivity(), and the handleLifecycleEvent() of the LifecycleRegistry class is called, The logic goes back to the LifecycleRegistry class, where events are distributed back to LifecycleRegistry

Look at an implementation of handleLifecycleEvent(Event) :

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);
        moveToState(next);
    }
Copy the code

Convert the distributed Event to State and then call moveToState() :

private void moveToState(State next) {
       
        // Update mState to the current StatemState = next; . mHandlingEvent =true;
        sync();
        mHandlingEvent = false;
    }
Copy the code

After updating the value of mState, sync() is called. This method is an important one in the LifecycleRegistry class.

Note that event is distributed, updating mSate without calling observers with the onStateChanged() callback.

All operations are handed over to the sync() method to synchronize and distribute events based on mState changes.

private void sync(a) { LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); .// Determine whether synchronization is required. If no synchronization is required, continue
      while(! isSynced()) { mNewEventOccurred =false;
          if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
             // Synchronize and distribute events
              backwardPass(lifecycleOwner);
          }
          Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
          if(! mNewEventOccurred && newest ! =null
                  && mState.compareTo(newest.getValue().mState) > 0) {				
                  // Synchronize and distribute events
              forwardPass(lifecycleOwner);
          }
      }
      mNewEventOccurred = false;
  }
Copy the code

The first step is to determine whether synchronization is needed by calling isSynced(), which is very simple to implement.

private boolean isSynced(a) {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    }
Copy the code

From the previous introduction we learned that the data structure that stores the Observer is an ordered Map.

By comparing the mState values of the first observer and the last observer, the synchronization is completed if the mState values are equal. If the mState values are not equal, the synchronization continues until the mState values are equal.

If the state of the first observer is equal to that of the last observer, the mSate of all intermediate observers must also be equal, thus marking the completion of synchronization.

In the forwardPass (lifecycleOwner) and forwardPass (lifecycleOwner); Method, we finally call the much-anticipated callback method: onStateChanged(), where our code is executed.

The whole process is analyzed.