Source code analysis of Android arch components - Lifecycle

Posted by marty_arl on Mon, 14 Feb 2022 13:09:01 +0100

The implementation of Lifecycle is similar to ViewModel, which uses fragment to realize its functions. By adding a fragment to the activity, the fragment can receive various life cycle callbacks.

The following source code uses version 2.2.0

Introduction to using method

I'm not going to talk too much about the usage of lifecycle here. Unfamiliar students can refer to it here.

In order to use lifecycle, you first need to obtain a lifecycle owner.

lifecycleOwner.getLifecycle().addObserver(observer);


public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

When using the support package, AppCompatActivity is a lifecycle owner. The specific implementation is SupportActivity:

public class SupportActivityextends Activity implements LifecycleOwner {}

Next, let's start with SupportActivity to analyze the implementation of lifecycle components.

SupportActivity

public class SupportActivity extends Activity implements LifecycleOwner {

    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Initialize ReportFragment
        ReportFragment.injectIfNeededIn(this);
    }
}

As you can see, in the previous section, we executed lifecycle owner What getlifecycle () returns is mllifecycle registry. About lifecycle registry, we'll look at it in the next section. Let's look at the ReportFragment first.

ReportFragment is what we said at the beginning, which is used to obtain the fragment of the life cycle:

public class ReportFragment extends Fragment {
    private static final String REPORT_FRAGMENT_TAG = "android.arch.lifecycle"
            + ".LifecycleDispatcher.report_fragment_tag";

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

    static ReportFragment get(Activity activity) {
        return (ReportFragment) activity.getFragmentManager().findFragmentByTag(
                REPORT_FRAGMENT_TAG);
    }

    private ActivityInitializationListener mProcessListener;

    private void dispatchCreate(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onCreate();
        }
    }

    private void dispatchStart(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onStart();
        }
    }

    private void dispatchResume(ActivityInitializationListener listener) {
        if (listener != null) {
            listener.onResume();
        }
    }

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

    private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        // For SupportActivity, the following is executed
        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }

    void setProcessListener(ActivityInitializationListener processListener) {
        mProcessListener = processListener;
    }

    interface ActivityInitializationListener {
        void onCreate();

        void onStart();

        void onResume();
    }
}

The implementation of ReportFragment is very simple. Just look at it for yourself. Let's start with the less understandable lifecycle registry.
Before looking at the code, let's first understand the status and events of Lifecycle:

public abstract class Lifecycle {

    public enum Event {
        /**
         * Constant for onCreate event of the {@link LifecycleOwner}.
         */
        ON_CREATE,
        /**
         * Constant for onStart event of the {@link LifecycleOwner}.
         */
        ON_START,
        /**
         * Constant for onResume event of the {@link LifecycleOwner}.
         */
        ON_RESUME,
        /**
         * Constant for onPause event of the {@link LifecycleOwner}.
         */
        ON_PAUSE,
        /**
         * Constant for onStop event of the {@link LifecycleOwner}.
         */
        ON_STOP,
        /**
         * Constant for onDestroy event of the {@link LifecycleOwner}.
         */
        ON_DESTROY,
        /**
         * An {@link Event Event} constant that can be used to match all events.
         */
        ON_ANY
    }

    /**
     * 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 state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
         * any more events. For instance, for an {@link android.app.Activity}, this state is reached
         * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
         */
        DESTROYED,

        /**
         * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
         * the state when it is constructed but has not received
         * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
         */
        INITIALIZED,

        /**
         * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
         *     <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
         * </ul>
         */
        CREATED,

        /**
         * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onStart() onStart} call;
         *     <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
         * </ul>
         */
        STARTED,

        /**
         * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached after {@link android.app.Activity#onResume() onResume} is called.
         */
        RESUMED;

        /**
         * Compares if this State is greater or equal to the given {@code state}.
         *
         * @param state State to compare with
         * @return true if this State is greater or equal to the given {@code state}
         */
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
}

Lifecycle.Event corresponds to each declaration cycle of activity, and State is the State of lifecycle. The conversion relationship between States is defined in lifecycle registry:

public class LifecycleRegistry extends Lifecycle {

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

These three methods can be summarized as the following figure:
downEvent indicates from one state to the state below it in the figure, and upEvent is upward.

After understanding the status of Lifecycle, let's continue to look at Lifecycle registry. In the previous section, we know that after the life cycle of an activity changes, it will call the handlelife cycleevent of LifecycleRegistry:

public class LifecycleRegistry extends Lifecycle {

    private int mAddingObserverCounter = 0;

    private boolean mHandlingEvent = false;
    private boolean mNewEventOccurred = false;

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

    private void moveToState(State next) {
        if (mState == next) {
            return;
        }
        mState = next;
        // When we trigger a state change when we call back LifecycleObserver in LifecycleRegistry,
        // mHandlingEvent is true;
        // When adding an observer, the callback method may also be executed. At this time, if a state change is triggered,
        // Then maddingobservercounter= 0
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // sync is not required.
            // The implementation here is: sync() - > lifecycleobserver - > movetostate()
            // After returning directly here, you will still return to sync() and continue to synchronize to the observer
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        // sync() will convert the state changes into lifecycle events and forward them to LifecycleObserver
        sync();
        mHandlingEvent = false;
    }
}

What lifecycle registry is supposed to do is actually very simple, but it introduces a lot of additional complexity because it needs to execute the customer's code. The reason is that the customer code is not under our control, and they may do anything they can. For example, here, a state change is triggered in the callback. Similarly, not calling the client code when holding the lock will also complicate the implementation.

Next, let's look at sync():

public class LifecycleRegistry extends Lifecycle {

    /**
     * Custom list that keeps observers and can handle removals / additions during traversal.
     *
     * This Invariant is very important. It will affect the logic of sync()
     * Invariant: at any moment of time for observer1 & observer2:
     * if addition_order(observer1) < addition_order(observer2), then
     * state(observer1) >= state(observer2),
     */
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();


    // happens only on the top of stack (never in reentrance),
    // so it doesn't have to take in account parents
    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "
                    + "new events from it.");
            return;
        }
        while (!isSynced()) {
            // mNewEventOccurred is to enable backwardPass/forwardPass() when the observer triggers a state change
            // For early return. We're just about to tune them. Set it to false here.
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                // The states of the elements in the mObserverMap are arranged non incrementally, that is, the state of the queue head is the largest
                // If the mState is smaller than the largest one in the queue, it indicates that there are elements that need to update the state
                // In order to maintain the Invariant of mObserverMap, we need to update the status of elements from the end of the queue to the front
                backwardPass(lifecycleOwner);
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            // If mnueventoccurred, it means that the customer triggered the status modification when calling backwardPass() above
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

    // If the status of all observer s has been synchronized, return true
    private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        // State = the head and tail of our team are enough, so state = the head and tail of our team are enough
        return eldestObserverState == newestObserverState && mState == newestObserverState;
    }

}

The main function of sync() is to synchronize the states of all elements in the mObserverMap to mState according to. Let's continue to look at the remaining backwardPass/forwardPass:

public class LifecycleRegistry extends Lifecycle {

    private ArrayList<State> mParentStates = new ArrayList<>();


    private void forwardPass(LifecycleOwner lifecycleOwner) {
        // Start iteration from the head of the team
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
                mObserverMap.iteratorWithAdditions();
        while (ascendingIterator.hasNext() && !mNewEventOccurred) {
            Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
            ObserverWithState observer = entry.getValue();
            while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                    // Maybe the customer removed himself when calling back the customer code
                    && mObserverMap.contains(entry.getKey()))) {
                // pushParentState and popParentState will be discussed in the next section. We will ignore them here
                pushParentState(observer.mState);
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
                popParentState();
            }
        }
    }

    private void backwardPass(LifecycleOwner lifecycleOwner) {
        // Start iteration at the end of the team
        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()))) {
                Event event = downEvent(observer.mState);
                pushParentState(getStateAfter(event));
                observer.dispatchEvent(lifecycleOwner, event);
                popParentState();
            }
        }
    }

    private void popParentState() {
        mParentStates.remove(mParentStates.size() - 1);
    }

    private void pushParentState(State state) {
        mParentStates.add(state);
    }
}

When looking at these two methods, you can refer to the above state diagram. For example, suppose that all the elements in the current queue are CREATED. Then I received an on_ As can be seen from the figure, the next step is to go to the STARTED state. Since STARTED is greater than CREATED, forwardPass() is executed. Call upEvent(observer.mState) in forwardpass () to return the event to be sent from CREATED to STARTED, that is, ON_START, then on_ The start event was sent to the customer.

Register / unregister observer

The registration of observer is completed by the addObserver method:

public class LifecycleRegistry extends Lifecycle {

    // This comment should be the most difficult to understand in the whole class, at least for me
    // we have to keep it for cases:
    // void onStart() {
    //     //removeObserver(this) indicates that this is a lifecycle observer
    //     //So what we're talking about here is that we perform the following two operations in the callback
    //     mRegistry.removeObserver(this);
    //     mRegistry.add(newObserver);
    // }
    // Suppose now we want to go from CREATED to STARTED (that is, mState is now STARTED).
    // In this case, only when the new observer is set to the CREATED state, its onStart will be called
    // In order to get this CREATED, mParentStates is introduced here. Execute in forwardPass
    // When pushParentState(observer.mState), observer MState is the CREATED we need.
    // The case of backwardPass is similar.
    // newObserver should be brought only to CREATED state during the execution of
    // this onStart method. our invariant with mObserverMap doesn't help, because parent observer
    // is no longer in the map.
    private ArrayList<State> mParentStates = new ArrayList<>();


    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;
        // Returns the smallest state
        return min(min(mState, siblingState), parentState);
    }

    @Override
    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;
        }

        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        // addObserver() was executed in the callback
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // We dispatch an event to the customer. When calling back the customer code, the customer may modify our status
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }


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

Due to the limited space, here's lifecycle Getcallback won't watch. Briefly, when using annotation, the corresponding observer will generate an adapter, which will put the corresponding lifecycle Replace event with method call:

static class BoundLocationListener implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void addLocationListener() {}

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void removeLocationListener() {}
}


// Generated code
public class BoundLocationManager_BoundLocationListener_LifecycleAdapter implements GeneratedAdapter {
  final BoundLocationManager.BoundLocationListener mReceiver;

  BoundLocationManager_BoundLocationListener_LifecycleAdapter(BoundLocationManager.BoundLocationListener receiver) {
    this.mReceiver = receiver;
  }

  @Override
  public void callMethods(LifecycleOwner owner, Lifecycle.Event event, boolean onAny,
      MethodCallsLogger logger) {
    boolean hasLogger = logger != null;
    if (onAny) {
      return;
    }
    if (event == Lifecycle.Event.ON_RESUME) {
      if (!hasLogger || logger.approveCall("addLocationListener", 1)) {
        mReceiver.addLocationListener();
      }
      return;
    }
    if (event == Lifecycle.Event.ON_PAUSE) {
      if (!hasLogger || logger.approveCall("removeLocationListener", 1)) {
        mReceiver.removeLocationListener();
      }
      return;
    }
  }
}

The implementation of logging off observer is relatively simple:

public class LifecycleRegistry extends Lifecycle {
    @Override
    public void removeObserver(@NonNull LifecycleObserver observer) {
        // we consciously decided not to send destruction events here in opposition to addObserver.
        // Our reasons for that:
        // 1. These events haven't yet happened at all. In contrast to events in addObservers, that
        // actually occurred but earlier.
        // 2. There are cases when removeObserver happens as a consequence of some kind of fatal
        // event. If removeObserver method sends destruction events, then a clean up routine becomes
        // more cumbersome. More specific example of that is: your LifecycleObserver listens for
        // a web connection, in the usual routine in OnStop method you report to a server that a
        // session has just ended and you close the connection. Now let's assume now that you
        // lost an internet and as a result you removed this observer. If you get destruction
        // events in removeObserver, you should have a special case in your onStop method that
        // checks if your web connection died and you shouldn't try to report anything to a server.
        mObserverMap.remove(observer);
    }
}

Congratulations, I believe you have a clear idea of the implementation of lifecycle and can pretend to be happy.

Topics: Java Android Android Studio