android LifeCycle - simple use and detailed principle analysis

Posted by coder_ on Mon, 31 Jan 2022 18:19:12 +0100

Pay attention to my official account: "an an an Android" "learn more knowledge"

What is Lifecycle used for

Lifecycle is used to store information about the lifecycle state of a component, such as an Activity or Fragment, and to allow other objects to observe this state.

More generally, you can get all the life cycle method callbacks of our activity by registering callbacks

The following figure shows all types of mechanisms for observing the life cycle

usage method

In general, the use of LifeCycle is very simple, and there is basically nothing to write. The chapter on the use method is limited to absolute novice reference.

It's futile. Let's start with a wave of simple code

Code display

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(MainObserver())
    }
}

class MainObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun create(){
        logEE("create")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start(){
        logEE("start")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun resume(){
        logEE("resume")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun pause(){
        logEE("pause")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop(){
        logEE("stop")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy(){
        logEE("destroy")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    fun any(){
        logEE("any")
    }
}

After running, we execute the following process:
Start app - click the back button to exit the app and view the life cycle log print:

Effect display

We found that all life cycle callbacks have been called, and on will be called synchronously immediately after each life cycle call_ Any annotation method

Handling abnormal states using LifeCycle

Description of abnormal state

The abnormal state I mentioned needs to give an example:

For example, we now start a time-consuming task to request the network, and then come back to update the ui after the network request is completed. Our abnormal state means that we actively shut down the activity before the network request is completed. Under normal circumstances, this time will cause memory leakage. Updating the ui again is obviously an abnormal state. In this example, we need to use LifeCycle to solve this kind of abnormal state.

Methods used

lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)

Test case description and Implementation

Case description:

Use thread in the onCreate method listener of the registered observer Sleep simulates a 4s time-consuming task, and then monitors the callback of the task in the Activity and prints the log. We need to simulate two operations:

  1. Do not close the page, wait for the time-consuming task to be completed, and view the log after the time-consuming task is completed
  2. Close the page before the end of the time-consuming task, and view the log after the end of the time-consuming task

Code display

Registered listener's observer Code:

 lifecycle.addObserver(MainObserver {
            runOnUiThread {
                if(lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)){
                    tv.text="Time consuming task completion"
                    logEE("Time consuming tasks completed and successfully updated ui")
                }else{
                    logEE("The lifecycle state does not match and cannot be updated ui")
                }
            }
        })

Code to handle time-consuming tasks:

 @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun create(){
        thread {
            Thread.sleep(4000)
            fun0()
        }
    }

Log corresponding to the two situations

Do not close the page and wait for the time-consuming task to be completed. View the log after the time-consuming task is completed:

Close the page before the end of the time-consuming task, and view the log after the end of the time-consuming task

conclusion

Is the LifeCycle using LifeCycle currentState. The isatleast (LifeCycle. State. Created) method can judge the current state of the Activity and handle the abnormal state flexibly

Implementation principle of LifeCycle

Basic principles

Let's talk about the basic principle first:

Our AppComponentActivity and FragmentActivity inherit ComponentActivity.

ComponentActivity implements the lifecycle owner interface.

A Fragment will be added to the onCreate lifecycle callback of ComponentActivity

So we use Fragment to realize the observation of life cycle

This implementation principle mechanism is not uncommon. For example, Glide and rxreservation are implemented in this way

I generally divide the code explanation into the following four parts

  1. Register Fragment in ComponentActivity

  2. Explanation of addObserver adding listener method

  3. Life cycle method linkage callback in Fragment

  4. How to callback annotation methods

After reading these four parts, you can fully understand the source code of LifeCycle

Explain the four parts of the code

Register Fragment in ComponentActivity

  1. Inject Fragment
    AppComponentActivity
ReportFragment.injectIfNeededIn(this);
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();
        }

This is mainly responsible for adding fragments to the activity

Explanation of addObserver method

  1. Method call

This method will call addObserver of LifecycleRegistry

 @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);
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        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();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

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

First, an ObserverWithState object will be created to record the lifecycle state,

State targetState = calculateTargetState(observer);

The accounting method calculates the life cycle state at this time,

This is followed by a while loop, which distributes the lifecycle state

For example, when you register in onResume, you can also receive the registration callback of onCreate and onStart. This registration method is actually sticky registration. The broadcast receiver of power information in Android system is a good sticky broadcast registration case, which is the same as this sticky registration principle

The method calls in the following code are as follows

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

The condition that isreentance is false is that no message is currently distributed in the moveToState method, or the number of registrants is not equal to 0. If this condition is met, the sync() method is called to distribute the message

Life cycle method linkage callback in Fragment

  1. Lifecycle method callback in ReportFragment
    For example:
dispatch(Lifecycle.Event.ON_DESTROY);
   private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
       ***

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }

In the code, all life cycle callbacks in the Fragment will call the dispatch method for distribution, and the dispatch method will call the handlelife cycleevent method of lifecycle to continue distribution

  1. Skip to the LifecycleRegistry class and find the handlelife cycleevent method
 public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);
        moveToState(next);
    }

The getStateAfter method is mainly used to confirm the state of the next life cycle when the event is triggered. There are three types:

CREATED,STARTED,DESTROYED

The moveToState method changes the lifecycle state and distributes it. The code is as follows:

 private void moveToState(State next) {
        if (mState == next) {
            return;
        }
        mState = next;
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }

The sync() method in moveToState is used to distribute lifecycle events to the Observer,

  1. sync() method
private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
        while (!isSynced()) {
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            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;
    }

The following code is several states of State

 public enum State {
      
        DESTROYED,
       
        INITIALIZED,
        
        CREATED,

        STARTED,

        RESUMED;
}

The while loop of sync method has the following code:

 if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }

The above line of code will compare the current life cycle state with the state first added to the safeiteratablemap. If it is less than zero (for example, the first added state is the INITIALIZED state, and the current state is smaller than ONCREATE, which can only be the de stroyed state), it indicates that the current life cycle needs to be processed by backwardPass

 Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }

In the above code, newest is the latest state added to the mObserverMap. If the current life cycle state is greater than the newest state, it indicates that the state is advancing (for example, onCreate to onStart)

  1. Continue to look at the backwardPass and forwardPass methods
 private void forwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
                mObserverMap.iteratorWithAdditions();//Gets an iterator in positive order
        while (ascendingIterator.hasNext() && !mNewEventOccurred) {
            Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
            ObserverWithState observer = entry.getValue();
            while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                pushParentState(observer.mState);
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
                popParentState();
            }
        }
    }

    private void backwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
                mObserverMap.descendingIterator();//Get inverse iterator
        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();
            }
        }
    }

Both forwardPass and backwardPass have three important codes:

pushParentState(getStateAfter(event));
observer.dispatchEvent(lifecycleOwner, event);
popParentState();

pushParentState(getStateAfter(event));

Save status to list

observer.dispatchEvent(lifecycleOwner, event);

Distribution status to Observer

popParentState();

Pop up the status stored in the previous code

  1. View the dispathchEvent method
  void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }

Mllifecycle observer onStateChanged(owner, event); Finally, it will call back to the annotation method we declared. The instance of mllifecycle observer is reflective genericlifecycle observer. Reflective genericlifecycle observer finally calls back the annotation method through reflection. This part will be described in detail in the next section

How to callback annotation methods

When it comes to annotation method callback, we have to mention addObserver method. In addObserver method of lifecycle registry class, we create an ObserverWithState object and put it into Map

In fact, in the construction of ObserverWithState method, the annotation method will be wrapped, and finally the reflection callback method will be used. Here is the code analysis:

The ObserverWithState method is constructed as follows

ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);

This line of code finally obtains the real type of the mlicycleobserver instance, which is ReflectiveGenericLifecycleObserver

The dispatchEvent method of ObserverWithState is as follows

void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }

In the dispatchEvent method, the

mLifecycleObserver.onStateChanged(owner, event);

Code for message distribution is actually calling reflectivegenericlifecycleobserver Onstatechanged method.

Let me take a look at the code in the reflective genericlifecycleobserver class

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    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);
    }
}

The wrapped object in the reflective genericlifecycleobserver class construction parameter is the custom Observer object registered in addObserver.

In the construction, through some reflection operations, the information in the Observer object is encapsulated into a CallbackInfo object.

Then when we call the onStateChanged method of ReflectiveGenericLifecycleObserver in ObserverWithState, we call the following code:

mInfo.invokeCallbacks(source, event, mWrapped);

The code of the method body of the invokeCallbacks method that has been subsequently called is as follows:

 @SuppressWarnings("ConstantConditions")
        void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) {
            invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);
            invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event,
                    target);
        }

        private static void invokeMethodsForEvent(List<MethodReference> 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);
                }
            }
        }

The above big piece of code will eventually call the following code of MethodReference

 void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
            //noinspection TryWithIdenticalCatches
            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 new RuntimeException(e);
            }
        }

This is the end, and finally pass

mMethod.invoke(target);

Execute our customized annotation method by calling java reflection method

Topics: Android source code analysis Lifecycle