preface

For Android development, we are certainly familiar with the Activity/Fragment lifecycle. Here is the official Activity lifecycle diagram:

The Fragment lifecycle diagram is shown below:

Callbacks to component life cycle functions have a strict order in Android, which is the basis for normal development and presentation of data. It is controlled by the Android system and we cannot interfere with it.

So it’s normal to do some logical processing in an Activity/Fragment lifecycle function, but this is perfectly normal and has some drawbacks that we’ll look at step by step.

The body of the

defects

In fact, the defects here are not a big problem, and we generally use them in daily use. There are two main points:

  • Too much logic in life cycle functions, such as initializing various data in onCreate and displaying it in onResume, can lead to logic confusion.

  • If I need to start a service in onStart and then close the service in onStop, but the service is a time-consuming operation, it is possible that the interface onStop has been called but the service is not started, and the error is caused.

Lifecycle is Lifecycle. If I separate these callback functions and put them in a class, I will do what I need to do in that class’s callback during that Lifecycle.

Summary of Lifecycle

Lifecycle holds the Lifecycle of the Activity/Fragement and allows other components to observe its state.

Basic Usage 1

Let’s take a look at the most basic usage:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    lifecycle.addObserver(object : LifecycleEventObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            Logger.d("source = $source event = $event")}}}Copy the code

As you can see the observer pattern used here by adding an observer to Lifecycle and notifying the observer when Lifecycle’s Lifecycle changes is very simple and runs as follows:

The result of the callback is an Event. What is this Event? As you can see from the name, it is an Event and corresponds to the previous Activity lifecycle function.

If it’s Fragement, you don’t need to test it, but it’s also a callback event.

Basic Usage 2

Lifecycle will also be used to determine the state of the View. For example, LiveData will have a feature that will not update the Activity/Fragment when it is not in the foreground.

This will determine the current State of the LifecycleOwner(Activity/Fragemnt). Since the Event callback is instantaneous, you need a variable that holds the current State of the View, which would normally require 6 or 7 states. Set the State to this State after each Event, so let’s look at the State:

public enum State {
    
    DESTROYED,

    INITIALIZED,

    CREATED,

    STARTED,

    RESUMED;
}
Copy the code

If I wanted to determine the state of an Activity after onPause, which should I use? So here’s a look at the source code to understand why.

Relationship between State and Event

Enumerations for all states are as follows:

public enum Event {
   
    ON_CREATE,
  
    ON_START,
   
    ON_RESUME,
    
    ON_PAUSE,
    
    ON_STOP,
    
    ON_DESTROY,
    
    ON_ANY;
    }
Copy the code

Lifecycle means calling events back and forth to indicate the current Lifecycle callback of an Activity/Fragment and then storing the current Lifecycle State through State.

There is a perfect illustration of the relationship between the two on the official website, that is, both ON_CREATE and ON_STOP callback events are CREATED State, which explains why there are fewer enumerations of State. In this case, I get that the current State is CREATED. The Activity is just finished executing ON_CREATE or ON_STOP, with questions, we explore the source code.

Relationships of several major classes

Lifecycle is very little code, but it is important and it is the foundation of the Jetpack component, so there are a few things that need to be made clear.

  • LifecycleOwner

Lifecycle holders. If a class implements Lifecycle, Lifecycle will be available. The code for this interface is as follows:

  • Lifecycle

This is the core lifecycle class, and its code is very simple, mainly consists of three methods, and two enumeration classes, enumeration class is the above State and Event, what are the three methods:

public abstract void addObserver(@NonNull LifecycleObserver observer);
Copy the code
public abstract void removeObserver(@NonNull LifecycleObserver observer);
Copy the code
public abstract State getCurrentState();
Copy the code

So when a class inherits Lifecycle it must be able to implement these methods.

  • LifecycleObserver

LifecycleObserver: A qualified lifecycle system must be able to observe changes in its lifecycle, so the LifecycleObserver interface is defined.

So after analyzing the above three basic interfaces, we understand the general design principle, and then we take a look at the source code with problems, mainly the following problems:

  • How the Lifecycle of an Activity/Fragment is passed to Lifecycle to be saved.

  • How to set the current state when the lifecycle method is called back.

  • How the observer model is implemented.

Source code analysis

Let’s take a look at the source code directly, although this part of the logic is not complicated, but to see the implementation of the source code to help us write code.

The same class

We usually write Activity inheritance to androidx. Appcompat. App. AppComponentActivity,

It inherits to androidx. Appcompat. App. FragmentActivity,

It inherits to androidx.activity.Com ponentActivity,

And its inheritance to androidx.core.app.Com ponentActivity,

The LifecycleOwner interface will be implemented in the LifecycleOwner interface.

This interface is implemented by two classes with the same name. The implementation method is the same for both classes:

You can see that the real implementation class here is LifecycleRegistry.

ReportFragment

I thought the onCreate, onResume, and other ComponentActivity methods would pass lifecycle callback events to mLifecycleRegistry. Instead, I found that mLifecycleRegistry has a class for distributing these events. This class is ReportFragment. In the onCreate method for ComponentActivity:

In ReportFragment:

We found that this is a normal Fragment, but life cycle distribution. There are also two cases where LifecycleCallbacks do it when SDK >= 29, and the Fragment life cycle does it otherwise.

The Fragment lifecycle callback can be dispatched in the Fragment lifecycle callback:

Here are six events distributed in the Fragment callback:

You’ll see that eventually all six events are passed into the handleLifecycleEvent function of LifecycleRegistry.

What happens when SDK >= 29? Let’s take a quick look:

First of all, this class is a static class and call the methods of dispatch of ReportFragment, so there must be in registerActivityLifecycleCallbacks in the Activity lifecycle callback function callback that several methods, we look at:

These methods are Activity methods, which I started with, which distribute events directly in Activity lifecycle functions.

So let’s look at the implementation of LifecycleRegistry.

LifecycleRegistry

Now that we know how an Activity/Fragment can pass Lifecycle events to Lifecycle, that is, call the method in LifecycleRegistry, which is responsible for collating dispatched Lifecycle events, Save the current State as well.

Although we know what LifecycleRegistry does, this class is a bit cumbersome to handle, so let’s take a closer look at it.

External call method

The above code calls this method to handle life cycle events:

Event.gettargetstate ()

We’ll see that we converted the six lifecycle events to four states and then called moveToState() :

So the heart of this is the moveToState function, but it defines so many Boolean flag bits that it’s hard to understand the subtlety of this design without looking at it carefully.

Let’s click off the table and look at the class in general.

The overall function

Let’s take a quick look at LifecycleRegistry’s three features:

  1. External activities/fragments send Event events to LifecycleRegistry
  2. Convert the Event passed in to State, which can be obtained by getCurrentState
  3. LifecycleRegistry registers observers and notifies them when the State of LifecycleRegistry changes

FastSafeIterableMap

Take a look at the source:

private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
        new FastSafeIterableMap<>();
Copy the code

FastSafeIterableMap is a container class, listen to the name it is a fast, safe Map, one of the key is added LifecycleObserver subscribers, the value is the encapsulation of the subscriber.

The reason for using this Map to store observers involves a principle called state ordering, which states that at any given moment the state of the new subscriber is less than or equal to all the previously subscribed subscribers.

The first thing to be clear about is that the state is not only stored in LifecycleRegistry, each observer also needs to save the state and call it back when it changes, but let’s look at the code for adding an observer:

It will be found that the State of the newly added observer is DESTROYED or INITALIZED, that is, the minimum value, which is not in accordance with the principle. As for the reason of the minimum value, we can see in the previous enumeration of State, the value relationship of State is as follows:

DESTROYED < INITIALIZED < CREATED < STARTED < RESUMED
Copy the code

If the current LifecycleRegistry is in a RESUMED State, so even if the observer was added after the onResume method was executed, the State saved by that observer should be set to a bit of RESUMED, not INITIALIZED. This leads to a feature, LifecycleObserver will call back to the state before it was added.

We can verify this by adding an Observer to the Activity’s onResume function:

override fun onResume() {
    super.onResume()
    lifecycle.addObserver(object : LifecycleEventObserver{
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            Logger.d("Event change: $event")}}}Copy the code

You’ll notice that the LifecycleObserver calls back to all three previous events

How to do this will be discussed later.

Add LifecycleObserver

Let’s look at the code to add a LifecycleObserver as follows:

public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    // Encapsulate the Observer to generate an instance of ObserverWithState
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // Save the key-value pair as observer
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
    // If previous is not empty, it has been added
    if(previous ! =null) {
        return;
    }
    // Use weak references to save LifecycleOwner
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }
    // Variables are defined here to prevent nesting operationsboolean isReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
    // Calculate to what level the state of the new observer needs to be raised
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    // When the State saved by the observer is less than the expected State, loop up the saved State
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        / / this
        pushParentState(statefulObserver.mState);
        // Raise the State. Return the Event in this State
        final Event event = Event.upFrom(statefulObserver.mState);
        if (event == null) {
            throw new IllegalStateException("no event up from " + statefulObserver.mState);
        }
        // Send events, since the above can only be promoted once, so here may send multiple events
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        / / this
        popParentState();
        // mState / subling may have been changed recalculate
        targetState = calculateTargetState(observer);
    }
    // Synchronization status
    if(! isReentrance) {// we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}
Copy the code

I’ve simply commented out the code to add LifecycleObserver, so the overall process should be clear, but let’s dig into the details and principles.

How ObserverWithState works

This part of the code design is very interesting, why to encapsulate here, if I were to design this, I might directly save the key value pair in the Map is LifecycleObserver, and value is State, wouldn’t that be more convenient?

Let’s look at the code:

static class ObserverWithState {
    // The State saved by the observer
    State mState;
    // Another class implements LifecycleObserver
    LifecycleEventObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) {
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    }
    // Distribute events
    void dispatchEvent(LifecycleOwner owner, Event event) {
        State newState = event.getTargetState();
        mState = min(mState, newState);
        // call back StatemLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code

Why not just save the observer in the constructor and call it back? Let’s look at the code for LifecycleObserver:

public interface LifecycleObserver {

}
Copy the code

LifecycleEventObserver is an interface that has no methods.

public interface LifecycleEventObserver extends LifecycleObserver {
    /**
     * Called when a state transition event happens.
     *
     * @param source The source of the event
     * @param event The event
     */
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
Copy the code

It’s a little bit more normal here, but there’s a method that we can use to call back. This explains the need to encapsulate a layer, since the LifecycleObserver interface does not define methods.

Here’s the problem: How can I achieve the desired effect without using LifecycleEvening Server? Of course, there is a way to use annotations. Example code is as follows:

lifecycle.addObserver(object : LifecycleObserver{

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun create(){
        Logger.d("zyh create")
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start(){
        Logger.d("zyh start")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun resume(){
        Logger.d("zyh resume")}})Copy the code

When an Event occurs, the method in its annotation will be called.

Here is more interesting, we usually write code rarely this, see how he is different implementation class callback to, without saying a word directly look at the code:

@NonNull
static LifecycleEventObserver lifecycleEventObserver(Object object) {
    // Check whether the two classes are commonly used
    boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
    boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
    / / if these two classes, that good solution, can be encapsulated into FullLifecycleObserverAdapter directly, in it
    // Make a callback
    if (isLifecycleEventObserver && isFullLifecycleObserver) {
        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
                (LifecycleEventObserver) object);
    }
    if (isFullLifecycleObserver) {
        return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
    }

    if (isLifecycleEventObserver) {
        return (LifecycleEventObserver) object;
    }
    // This is the Observer converted to when the Annotation Processor is usedfinal Class<? > klass = object.getClass(); int type = getObserverConstructorType(klass);if (type == GENERATED_CALLBACK) {
        List<Constructor<? extends GeneratedAdapter>> constructors =
                sClassToAdapters.get(klass);
        if (constructors.size() == 1) {
            GeneratedAdapter generatedAdapter = createGeneratedAdapter(
                    constructors.get(0), object);
            return new SingleGeneratedAdapterObserver(generatedAdapter);
        }
        GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
        for (int i = 0; i < constructors.size(); i++) {
            adapters[i] = createGeneratedAdapter(constructors.get(i), object);
        }
        return new CompositeGeneratedAdaptersObserver(adapters);
    }
    // An Observer generated by reflection is generated when using the above code to annotate functions using annotations
    / / the Observer
    return new ReflectiveGenericLifecycleObserver(object);
}
Copy the code

First look at the simple FullLifecycleObserverAdapter source, this is when the Observer is LifecycleEventObserver and FullLifecycleObserver registered call, the code is as follows:

class FullLifecycleObserverAdapter implements LifecycleEventObserver {
    // Contains two instances of classes
    private final FullLifecycleObserver mFullLifecycleObserver;
    private final LifecycleEventObserver mLifecycleEventObserver;

    FullLifecycleObserverAdapter(FullLifecycleObserver fullLifecycleObserver, LifecycleEventObserver lifecycleEventObserver) {
        // If it is one, the other is passed null
        mFullLifecycleObserver = fullLifecycleObserver;
        mLifecycleEventObserver = lifecycleEventObserver;
    }

    // This method goes without saying. This is what is returned in the encapsulated ObserverWithState
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        switch (event) {
            case ON_CREATE:
                mFullLifecycleObserver.onCreate(source);
                break;
            case ON_START:
                mFullLifecycleObserver.onStart(source);
                break;
            case ON_RESUME:
                mFullLifecycleObserver.onResume(source);
                break;
            case ON_PAUSE:
                mFullLifecycleObserver.onPause(source);
                break;
            case ON_STOP:
                mFullLifecycleObserver.onStop(source);
                break;
            case ON_DESTROY:
                mFullLifecycleObserver.onDestroy(source);
                break;
            case ON_ANY:
                throw new IllegalArgumentException("ON_ANY must not been send by anybody");
        }
        // With a callback
        if(mLifecycleEventObserver ! =null) { mLifecycleEventObserver.onStateChanged(source, event); }}}Copy the code

This method is no problem for us to understand, just as we usually write callback, the difficulty is to use annotations below.

Let’s take a look at the use of annotations, using the Observer source:

// The class name is the Observer generated by reflection
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    private final Object mWrapped;
    // The method that needs a callback
    private final CallbackInfo mInfo;

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

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) {
        // Make a callbackmInfo.invokeCallbacks(source, event, mWrapped); }}Copy the code

If we look at the implementation of the key ClassesInfoCache class, we can probably guess that we should use the annotation to find the corresponding method and then call it. Let’s see if this is the case:

CallbackInfo getInfo(Class
        klass) {
    // Check whether there is a cache
    CallbackInfo existing = mCallbackMap.get(klass);
    if(existing ! =null) {
        return existing;
    }
    / / new
    existing = createInfo(klass, null);
    return existing;
}
Copy the code

See how to create CallbackInfo:

private CallbackInfo createInfo(Class
        klass, @Nullable Method[] declaredMethods){ Class<? > superclass = klass.getSuperclass();//HashMap, where key is method and value is corresponding Event
    Map<MethodReference, Lifecycle.Event> handlerToEvent = new HashMap<>();
    if(superclass ! =null) {
        // If the parent class has CallbackInfo, add it as well
        CallbackInfo superInfo = getInfo(superclass);
        if(superInfo ! =null) { handlerToEvent.putAll(superInfo.mHandlerToEvent); }}// Determine if any methods need to be added to the implemented interfaceClass<? >[] interfaces = klass.getInterfaces();for(Class<? > intrfc : interfaces) {for (Map.Entry<MethodReference, Lifecycle.Event> entry : getInfo( intrfc).mHandlerToEvent.entrySet()) { verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass); }}// Get method information daily by reflectionMethod[] methods = declaredMethods ! =null ? declaredMethods : getDeclaredMethods(klass);
    boolean hasLifecycleMethods = false;
    for (Method method : methods) {
        OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
        if (annotation == null) {
            continue;
        }
        // When the method has an OnLifecycleEvent annotation
        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"); }}// Get the annotation information for this method
        Lifecycle.Event event = annotation.value();

        if (params.length > 1) {
            callType = CALL_TYPE_PROVIDER_WITH_EVENT;
            if(! params[1].isAssignableFrom(Lifecycle.Event.class)) {
                throw new IllegalArgumentException(
                        "invalid parameter type. second arg must be an event");
            }
            if(event ! = Lifecycle.Event.ON_ANY) {throw new IllegalArgumentException(
                        "Second arg is supported only for ON_ANY value"); }}if (params.length > 2) {
            throw new IllegalArgumentException("cannot have more than 2 params");
        }
        // Wrap the method into the MethodReference class
        MethodReference methodReference = new MethodReference(callType, method);
        verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
    }
    CallbackInfo info = new CallbackInfo(handlerToEvent);
    mCallbackMap.put(klass, info);
    mHasLifecycleMethods.put(klass, hasLifecycleMethods);
    return info;
}
Copy the code

Take a look at this MethodReference class:

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

    // Here we pass in the method and call type
    MethodReference(int callType, Method method) {
        mCallType = callType;
        mMethod = method;
        mMethod.setAccessible(true);
    }

    void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
        //noinspection TryWithIdenticalCatches
        try {
            switch (mCallType) {
                // The annotated function is divided into one and two parameters
                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

Sure enough, this is done by finding the function that defines the annotation in the anonymous class and invoking it when appropriate.

conclusion

As this chapter continues, Lifecycle and ObserverWithState will look at how FastSafeIterableMap works and the role of various flag bits.