This article was first published on the wechat official account “Houchang Village Code Nong”.

preface

In the last article we learned how to use Lifecycle. Of course knowing how to use Lifecycle is not enough. Understanding how it works is essential to be a good engineer. In this article we will study the fundamentals of Lifecycle.

1.Lifecycle specifies the Lifecycle status events and states

Lifecycle uses two enumerations, Event and State, to track the Lifecycle State of its associated components. State refers to the State that Lifecycle is in. Event represents the events corresponding to the Lifecycle Lifecycle that are mapped to callback events in the Activity and Fragment.

The Android 9.0 source code for Lifecycle is shown below. frameworks/support/lifecycle/common/src/main/java/androidx/lifecycle/Lifecycle.java

public abstract class Lifecycle {
   
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);

    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);

    @MainThread
    @NonNull
    public abstract State getCurrentState(a);

    @SuppressWarnings("WeakerAccess")
    public enum Event {
        ON_CREATE,
        ON_START,
        ON_RESUME,
        ON_PAUSE,
        ON_STOP,
        ON_DESTROY,
        ON_ANY
    }

    @SuppressWarnings("WeakerAccess")
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0; }}}Copy the code

Lifecycle is an abstract class that includes not only the methods to add and remove observers but also the Event and State enumerations mentioned earlier. As you can see, the events in Event correspond to the lifecycle of the Activity, except ON_ANY, which can be used to match all events.

The relationship between State and Event is shown in the following sequence diagram.

2. How does Lifecycle observe the Lifecycle of activities and fragments

In Android Support Library versions 26.1.0 and later, activities and fragments already implement the LifecycleOwner interface by default. LifecycleOwner can be understood as the observed, So how does Lifecycle observe the Lifecycle of activities and fragments?

In the example from the previous article, MainActivity inherits AppCompatActivity, which inherits FragmentActivity. On Android 8.0, FragmentActivity inherits from SupportActivity, and on Android 9.0, FragmentActivity inherits from ComponentActivity. The code for SupportActivity and ComponentActivity is not very different. Here we use ComponentActivity as an example, as shown below.

frameworks/support/compat/src/main/java/androidx/core/app/ComponentActivity.java

@RestrictTo(LIBRARY_GROUP)
public class ComponentActivity extends Activity implements LifecycleOwner {
    private SimpleArrayMap<Class<? extends ExtraData>, ExtraData> mExtraDataMap =
            new SimpleArrayMap<>();

    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);/ / 1

    @RestrictTo(LIBRARY_GROUP)
    public void putExtraData(ExtraData extraData) {
        mExtraDataMap.put(extraData.getClass(), extraData);
    }

    @Override
    @SuppressWarnings("RestrictedApi")
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);/ / 2
    }

    @CallSuper
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        mLifecycleRegistry.markState(Lifecycle.State.CREATED);/ / 3
        super.onSaveInstanceState(outState);
    }

    @RestrictTo(LIBRARY_GROUP)
    public <T extends ExtraData> T getExtraData(Class<T> extraDataClass) {
        return (T) mExtraDataMap.get(extraDataClass);
    }

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

    @RestrictTo(LIBRARY_GROUP)
    public static class ExtraData {}}Copy the code

LifecycleRegistry is created in note 1, which is Lifecycle’s implementation class. Note 4 implements the getLifecycle method defined by the LifecycleOwner interface, returning LifecycleRegistry. In comment 3, Lifecycle’s State is set to CREATED. Lifecycle’s State should normally be changed in the Lifecycle methods of the ComponentActivity. This is not done in The ReportFragment. Instead, Lifecycle’s State should be changed in the ReportFragment. Inject ComponentActivity into the ReportFragment in Note 2.

frameworks/support/lifecycle/runtime/src/main/java/androidx/lifecycle/ReportFragment.java

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class ReportFragment extends Fragment {
    private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"
            + ".LifecycleDispatcher.report_fragment_tag";
    public static void injectIfNeededIn(Activity activity) {
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(newReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); }}static ReportFragment get(Activity activity) {
        return(ReportFragment) activity.getFragmentManager().findFragmentByTag( REPORT_FRAGMENT_TAG); }...@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

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

    @Override
    public void onResume(a) {
        super.onResume(); dispatchResume(mProcessListener); dispatch(Lifecycle.Event.ON_RESUME); }...private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) {/ / 2
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {/ / 3
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceofLifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); }}}... }Copy the code

The onStart method of the ReportFragment calls the Dispatch method in note 1. In note 2 of the Dispatch method, determine whether the Activity implements the LifecycleRegistryOwner interface. LifecycleRegistryOwner inherits the LifecycleOwner interface. The difference between the two interfaces is that The getLifecycle method defined by LifecycleRegistryOwner returns type LifecycleRegistry, while the getLifecycle method defined by LifecycleOwner returns type Lifecycle. Note 3 If the Activity implements the LifecycleOwner interface, LifecycleRegistry’s handleLifecycleEvent method is called. frameworks/support/lifecycle/runtime/src/main/java/androidx/lifecycle/LifecycleRegistry.java

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

The getStateAfter method gets the upcoming event: what event will be in the upcoming event after the current event is executed, as shown below.

   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);
    }
Copy the code

This makes sense when compared to the sequence diagram of the relationship between State and Event shown at the beginning of this article. For example, if an ON_CREATE Event or ON_STOP Event is currently executed, then the State is CREATED. Going back to the handleLifecycleEvent method, it also calls the moveToState method internally.

   private void moveToState(State next) {
        if (mState == next) {
            return;
        }
        mState = next;
        if(mHandlingEvent || mAddingObserverCounter ! =0) {
            mNewEventOccurred = true;
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }
Copy the code

If the current state is the same as the state you are going to be in then do nothing. The sync method is shown below.

  private void sync(a) {
        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 =false;
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if(! mNewEventOccurred && newest ! =null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }
    
Copy the code

The sync method compares the current state to the newest and eldest states in the mObserverMap to determine whether the current state is forward or backward. For example, from STARTED to RESUMED is the state forward, and the opposite is the state backward. This is not to be confused with the Activity lifecycle. The forward or backward code is pretty much the same, so here’s the backward example.

    private void forwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
                mObserverMap.iteratorWithAdditions();
        while(ascendingIterator.hasNext() && ! mNewEventOccurred) { Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next(); ObserverWithState observer = entry.getValue();/ / 1
            while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                pushParentState(observer.mState);
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));/ / 2popParentState(); }}}Copy the code

Note 1 is used to get ObserverWithState, which will be mentioned later. The upEvent method in note 2 returns a forward state of the current state. The dispatchEvent method for ObserverWithState is shown below.

frameworks/support/lifecycle/runtime/src/main/java/androidx/lifecycle/LifecycleRegistry.java

    static class ObserverWithState {
        State mState;
        GenericLifecycleObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);/ / 1
            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

As you can see from the name, it contains State and GenericLifecycleObserver internally. GenericLifecycleObserver is an interface that inherits from the LifecycleObserver interface. ReflectiveGenericLifecycleObserver and CompositeGeneratedAdaptersObserver is GenericLifecycleObserver implementation class, This main view ReflectiveGenericLifecycleObserver onStateChanged method is how to implement. frameworks/support/lifecycle/common/src/main/java/androidx/lifecycle/ReflectiveGenericLifecycleObserver.java

class ReflectiveGenericLifecycleObserver implements GenericLifecycleObserver {
    private final Object mWrapped;
    private final CallbackInfo mInfo;

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

    @Override
    public void onStateChanged(LifecycleOwner source, Event event) {
        mInfo.invokeCallbacks(source, event, mWrapped);/ / 1}}Copy the code

Note 1 calls the invokeCallbacks method of CallbackInfo. Before we talk about this method, we need to understand how CallbackInfo is created. It is created by the createInfo method, as shown below.

 private CallbackInfo createInfo(Class klass, @Nullable Method[] declaredMethods) {
        Class superclass = klass.getSuperclass();
        Map<MethodReference, Lifecycle.Event> handlerToEvent = newHashMap<>(); . Method[] methods = declaredMethods ! =null ? declaredMethods : getDeclaredMethods(klass);
        boolean hasLifecycleMethods = false;
        for (Method method : methods) {
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);/ / 1
            if (annotation == null) {
                continue;
            }
            hasLifecycleMethods = true; 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");
                }
            }
            Lifecycle.Event event = annotation.value();/ / 2. MethodReference methodReference =new MethodReference(callType, method);/ / 3
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);/ / 4
        }
        CallbackInfo info = new CallbackInfo(handlerToEvent);/ / 5
        mCallbackMap.put(klass, info);
        mHasLifecycleMethods.put(klass, hasLifecycleMethods);
        return info;
    }
Copy the code

The key point is at comment 1, constantly iterating through the methods to get the OnLifecycleEvent annotation on the method, which is used to implement the LifecycleObserver interface. Get the value of this annotation at annotation 2, which is the event defined in @onlifecyCleEvent. A new MethodReference is created in note 3, which contains the method that uses the annotation. The verifyAndPutHandler method in note 4 is used to place a MethodReference and its corresponding Event in a handlerToEvent of type Map

. Create a new CallbackInfo at comment 5 and pass in the handlerToEvent.
,>

Next, look back at the invokeCallbacks method for CallbackInfo, as shown below. frameworks/support/lifecycle/common/src/main/java/androidx/lifecycle/ClassesInfoCache.java

static class CallbackInfo {
        final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers;
        final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;
        CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) {
            mHandlerToEvent = handlerToEvent;
            mEventToHandlers = new HashMap<>();
            for (Map.Entry<MethodReference, Lifecycle.Event> entry : handlerToEvent.entrySet()) {/ / 1
                Lifecycle.Event event = entry.getValue();
                List<MethodReference> methodReferences = mEventToHandlers.get(event);
                if (methodReferences == null) {
                    methodReferences = newArrayList<>(); mEventToHandlers.put(event, methodReferences); } methodReferences.add(entry.getKey()); }}@SuppressWarnings("ConstantConditions")
        void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) {
            invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);/ / 2
            invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event,
                    target);
        }

        private static void invokeMethodsForEvent(List
       
         handlers, LifecycleOwner source, Lifecycle.Event event, Object mWrapped)
        {
            if(handlers ! =null) {
                for (int i = handlers.size() - 1; i >= 0; i--) {
                    handlers.get(i).invokeCallback(source, event, mWrapped);/ / 1}}}Copy the code

The significance of the loop in note 1 is to convert the handlerToEvent into a HashMap, where the value of key is the event and the value of value is MethodReference. The invokeMethodsForEvent method in comment 2 passes mEventToHandlers. Get (event), which is a collection of the MethodReference corresponding to the event. The invokeMethodsForEvent method traverses the collection of MethodReference and invokes the invokeCallback method of MethodReference.

frameworks/support/lifecycle/common/src/main/java/androidx/lifecycle/ClassesInfoCache.java

 @SuppressWarnings("WeakerAccess")
    static class MethodReference {
        final int mCallType;
        final Method mMethod;
        MethodReference(int callType, Method method) {
            mCallType = callType;
            mMethod = method;
            mMethod.setAccessible(true);
        }
        void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
            try {
                switch (mCallType) {
                    case CALL_TYPE_NO_ARG:
                        mMethod.invoke(target);
                        break;
                    case CALL_TYPE_PROVIDER:
                        mMethod.invoke(target, source);
                        break;
                    case CALL_TYPE_PROVIDER_WITH_EVENT:
                        mMethod.invoke(target, source, event);
                        break; }}catch (InvocationTargetException e) {
                throw new RuntimeException("Failed to call observer method", e.getCause());
            } catch (IllegalAccessException e) {
                throw newRuntimeException(e); }}... }Copy the code

The MethodReference class has two variables, callType, which represents the type of the calling Method, and Method, which represents the Method, and either callType reflects the Method through Invoke. In simple terms, in classes that implement the LifecycleObserver interface, annotated methods and events are saved, and the corresponding methods of the events are called through reflection. The timing diagram for this call chain is shown below.

3. The Lifecycle association class

In Section 2, Lifecycle is introduced in the form of a call chain. It is difficult to fully grasp the specific relationships of the classes involved in the call chain. Therefore, Lifecycle association class is presented in the form of UML diagram here, version of which is Android 9.0.

AppCompatActivity extends from FragmentActivity, neither of which is considered a Lifecycle association class. LifecycleOwner interface is implemented by FragmentActivity. LifecycleOwner and Lifecycle have a “weak ownership relationship”. LifecycleRegistry inherits from Lifecycle. If you don’t understand UML class diagrams, you can read The book Design Patterns.

For more, check out my independent blog Body of Knowledge: liuwangshu.cn/system/


Here we share not only big front-end, Android, Java and other technologies, but also programmer growth articles.