preface

The previous articles have laid the foundation for Jetpack and this article will begin with Lifecycle and begin with a formal analysis of Jetpack components. Through this article you will learn:

1. Why Lifecycle is needed? How will Lifecycle be used? Lifecycle 4. Lifecycle memory leaks 5, summary

1. Why Lifecycle is needed?

The beginning of the life cycle

Common components with a life cycle in Android include Activity, Fragment, Service, etc. Among them, Activity and Fragment are the most common, and the life cycle of Fragment depends on Activity, so we can master the life cycle of Activity. Nothing else. The Android Activity life cycle is full of ups and downs

Life cycle application

Bronze player

As a simple example, the simplest way to stop a network request when an Activity exits (loses focus) is to start the Activity with a network request:

    @Override
    protected void onResume() {
        super.onResume();
        NetRequest.startRequest();
    }

    @Override
    protected void onPause() {
        super.onPause();
        NetRequest.stopRequest();
    }
Copy the code

Override the onResume() method. When this method is called, the Activity is in focus and the page is about to be displayed, at which point network requests can be made to pull data. Override the onPause() method. When called, the Activity loses focus and no longer needs to request the network. That seems fine, but think about it: The onResume() and onPause() methods add a lot of code to the onResume() and onPause() methods, making the Activity bloated.

The silver player

It doesn’t matter, I have MVP architecture that encapsulates this business logic with Presenter. Declare the Presenter class: LifecyclePresenter.

public class LifecyclePresenter implements ILifecycle{ @Override public void onResume() { NetRequest.startRequest(); } @Override public void onPause() { NetRequest.stopRequest(); }}Copy the code

This class implements the interface ILifecycle, which declares methods that match the Activity lifecycle:

interface ILifecycle {
    void onCreate();
    void onStart();
    void onResume();
    void onPause();
    void onStop();
    void onDestroy();
}
Copy the code

Okay, finally, listen for life cycle changes in the Activity and call the LifecyclePresenter methods:

    @Override
    protected void onResume() {
        super.onResume();
        lifecyclePresenter.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        lifecyclePresenter.onPause();
    }
Copy the code

This way, other business logic can be added to the LifecyclePresenter method in the future, reducing the workload of the Activity.

Gold players

Although there is only one new line of code in each method of the Activity lifecycle, it is best to decouple the UI from the logic. For example, in the division of labor, someone who is responsible for the UI may not care about when to start/end the network request, which is written by the student who is responsible for the specific business logic. How do you do that? Remember on the analysis of the Activity lifecycle has said: the Activity provides registerActivityLifecycleCallbacks (the callback) method, when the Activity life cycle change will invoke the method. So we can listen for life cycle changes here and call the corresponding business code:

public class LifecycleHelper {
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static void bindLifecycle(Activity activity, ILifecycle iLifecycle) {
        if (activity == null)
            return;
        activity.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityResumed(@NonNull Activity activity) {
                if (iLifecycle != null)
                    iLifecycle.onResume();
            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {
                if (iLifecycle != null)
                    iLifecycle.onPause();
            }
        });
    }
}
Copy the code

The incoming Activity is the Activity that wants to listen for its life cycle.

public class LifecyclePresenterV2 { @RequiresApi(api = Build.VERSION_CODES.Q) public LifecyclePresenterV2(Activity activity) { LifecycleHelper.bindLifecycle(activity, new ILifecycle() { @Override public void onResume() { NetRequest.startRequest(); } @Override public void onPause() { NetRequest.stopRequest(); }}); }}Copy the code

Change Presenter to LifecyclePresenterV2. In this case, the Activity simply calls:

LifecyclePresenterV2 LifecyclePresenterV2 = new LifecyclePresenterV2(this);Copy the code

As can be seen:

Instead of rewriting the callback methods for each lifecycle, you can place the logic in a separate business layer with just one line of code, and bind the lifecycle to the specific business, depending on the business needs and lifecycle linkage.

If the Activity is subsequently changed, the business at the logical layer does not change.

Everything seems all right? No, look at registerActivityLifecycleCallbacks () method calls are limited version: RequiresApi(API = build.version_codes.q) means that the API must be at least Android 10(29) in order to be called, which is extremely limited.

The introduction of the Lifecycle

From the above analysis, we can perceive that the linkage scenarios between life cycle and business are quite rich, and we really need a set of tools to help us simplify the linkage process.

Google said Lifecycle and there will be Lifecycle.

Lifecycle source code is not complicated, it does three things:

An interface that allows the outside world to listen on a phase in the lifecycle of interest (onResume, onPause, onDestroy, etc.) while the outside world is acting as an observer. 2. Listen for the Activity lifecycle somewhere, where the Activity is being observed. 3. Inform the observer of the lifecycle.

How will Lifecycle be used?

Add observer

Lifecycle as we can see from Lifecycle three things, the outside world can listen for Lifecycle changes simply by adding a observing interface and handling the corresponding Lifecycle in the callback method of the interface. There are two different ways:

1. Annotating the observations

Earlier versions of Lifecycle used annotations to simplify the observer in order to minimize overwriting methods in the interface.

Class MyObserver7 implements LifecycleObserver {@onlifecycleEvent (Lifecycle.event.on_pause) void onPause() {MyObserver7 implements LifecycleObserver. Log.d(TAG, "onPause"); }}Copy the code

The focus here is onPause only, but if you want to monitor other state changes, you can simply add annotations to the corresponding state. Then listen in the Activity:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);

        getLifecycle().addObserver(new MyObserver7());
    }
Copy the code

The onPause() method in MyObserver7 is called when the Activity loses focus. As you can see, all you need to do in the Activity is add an observer.

2. Interface processing of observation results

Lifecycle deprecates annotation viewing and uses interfaces instead, which is recommended if you use Java8 or have Java8 features enabled.

//Java8 class MyObserver8 implements DefaultLifecycleObserver {@override public void onPause(LifecycleOwner owner) {  Log.d(TAG, "pause"); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle); getLifecycle().addObserver(new MyObserver8()); }Copy the code

As you can see, the DefaultLifecycleObserver interface is implemented, which inherits the FullLifecycleObserver interface.

interface FullLifecycleObserver extends LifecycleObserver {
    void onCreate(LifecycleOwner owner);
    void onStart(LifecycleOwner owner);
    void onResume(LifecycleOwner owner);
    void onPause(LifecycleOwner owner);
    void onStop(LifecycleOwner owner);
    void onDestroy(LifecycleOwner owner);
}
Copy the code

The DefaultLifecycleObserver interface implements all of the FullLifecycleObserver methods by default

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {
    }
    ....
Copy the code

You can see the use of a new Java8 feature: default decorates interface methods. So when we implement the DefaultLifecycleObserver interface, we just need to rewrite the interface corresponding to the state of interest.

How will Lifecycle be perceived

To sum up, through the Lifecycle can be easily perceive the change of the Activity Lifecycle, the front part, step by step, we also analysis how to encapsulate Lifecycle unfortunately met registerActivityLifecycleCallbacks versions limit problem, Let’s see how Lifecycle gets around the restrictions.

Step 1: Register an observer

LifecycleRegistry

Both the interface and the annotations use getLifecycle(), which returns an object that Lifecycle is an abstract class, and getLifecycle() returns an object that is a subclass of Lifecycle: LifecycleRegistry.

#ComponentActivity.java
    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
Copy the code

When a custom Activity inherits from AppCompatActivity, and ComponentActivity is a parent of AppCompatActivity, So a custom Activity that calls getLifecycle() returns the mLifecycleRegistry object. The mLifecycleOwner object in LifecycleRegistry is the custom Activity itself (weak reference).

addObserver()

#LifecycleRegistry.java @Override public void addObserver(@NonNull LifecycleObserver observer) { Lifecycle.State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED; // Pass to observer, Tectonic ObserverWithState LifecycleRegistry. ObserverWithState statefulObserver = new LifecycleRegistry.ObserverWithState(observer, initialState); / / will ObserverWithState added to the map in LifecycleRegistry. ObserverWithState previous = mObserverMap. PutIfAbsent (the observer, statefulObserver); . }Copy the code

The key is ObserverWithState:

#LifecycleRegistry. Java static class ObserverWithState {// Lifecycle.State mState; // LifecycleEventObserver mLifecycleObserver; ObserverWithState(LifecycleObserver observer, Lifecycle. State initialState) {/ / packaging mLifecycleObserver = Lifecycling observer. LifecycleEventObserver (observer); mState = initialState; } void dispatchEvent(LifecycleOwner owner, Lifecycle.Event Event) { State newState = Event.gettargetState (); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; }}Copy the code

Then look at Lifecycling. LifecycleEventObserver:

Java static LifecycleEventObserver LifecycleEventObserver (Object Object) {// Interface mode Boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver; . If (isFullLifecycleObserver) {// If the observer is an interface, Direct return to return new FullLifecycleObserverAdapter ((FullLifecycleObserver) object, null); } // Process the annotations, record the annotations, and next time fetch the final Class<? > klass = object.getClass(); int type = getObserverConstructorType(klass); . return new ReflectiveGenericLifecycleObserver(object); }Copy the code

The focus of addObserver() is to wrap the Observer into a Map with some columns.

The obvious thing to think about is that when the lifecycle changes, the observer will be pulled from the Map and notified.

Step 2: Lifecycle changes – notify the observer

Android10(inclusive) above processing

The best way to understand how Lifecycle informs the observer is to look at its call stack through a breakpoint. For example, when an observer is called, the call stack is as follows:

Attention to the Activity. The dispatchActivityPostStarted () method:

# Activity. Java private void dispatchActivityPostStarted () {/ / find the listener Object [] callbacks = collectActivityLifecycleCallbacks(); if (callbacks ! = null) { for (int i = 0; i < callbacks.length; I++) {/ / call the callback method ((Application. ActivityLifecycleCallbacks) callbacks [I]). OnActivityPostStarted (this); }}... }Copy the code

But here’s the listener is through Activity. The registerActivityLifecycleCallbacks (the callback) to register. The callback is: ReportFragment LifecycleCallbacks object, the object of registered in:

#ReportFragment.java public static void injectIfNeededIn(Activity activity) { if (Build.VERSION.SDK_INT >= 29) { / / if is Android10 above, the direct registration ActivityLifecycleCallbacks ReportFragment. LifecycleCallbacks. RegisterIn (activity); } / / will be added to the Activity in an empty fragments. 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(); }}Copy the code

InjectIfNeededIn is called in activity.onCreate (). Ok, now we know:

When an Activity is created, listen for changes in the Activity state with The ReportFragment.

According to the system version, There are two listening modes of ReportFragment:

1, the Android 10 above (contain) equipment through registerActivityLifecycleCallbacks () listening. 2. Under Android 10, listening is done through fragments.

At this point Lifecycle is simply listening to the state of the Activity and will need to distribute that state. Again, Android10 handles this as an example:

#ReportFragment.java static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) { ... If (Activity instanceof LifecycleOwner) {Lifecycle, LifecycleRegistry Lifecycle = ((LifecycleOwner) activity).getLifecycle(); If (lifecycle instanceof LifecycleRegistry) {// Lifecycle instanceof LifecycleRegistry). HandleLifecycleEvent (event); }}}Copy the code

The Event is handled by LifecycleRegistry, which uses the Event and State transitions to find the corresponding encapsulated Observer in the Map and notify the registered Observer in the Activity. Notification of a life cycle state change is now complete.

Android 10 does the following

We know that when a Fragment is associated with an Activity, its life cycle is associated with the Activity. What does Android Fragment want you to use?

So when the Activity lifecycle changes, a Fragment method is called, using the onStart() state as an example:

#ReportFragment.java @Override public void onStart() { super.onStart(); dispatchStart(mProcessListener); // Dispatch events (Lifecycle. Event.on_start); } private void dispatch(@nonnull Lifecycle.Event Event) {if (build.version.sdk_int < 29) {//Android 10 dispatch(getActivity(), event); }}Copy the code

At this point, we know how the Lifecycle processing registerActivityLifecycleCallbacks () versions limit question: is the upper by ReportFragment the caller to change the details of the screen to monitor the Activity life cycle. Used in Android (including) above 10 registerActivityLifecycleCallbacks (), under its use empty fragments added to the Activity.

Lifecycle indicates the perception Lifecycle

It is shown as follows:

Green:

Lifecycle listens for Activity Lifecycle changes.

Blue:

The outside world registers observers through Lifecycle.

Red:

Lifecycle listens until the Lifecycle changes, notifying the observer.

Lifecycle memory leak?

Add the following code to the Activity(assuming custom LifeActivity) onCreate() to monitor the Activity lifecycle:

        getLifecycle().addObserver(new DefaultLifecycleObserver() {
            @Override
            public void onCreate(@NonNull @org.jetbrains.annotations.NotNull LifecycleOwner owner) {
                
            }
        });
Copy the code

The question is: Do I need to remove the observer in activity.ondestroy ()? We know that the anonymous inner class holds a reference to the external class, addObserver(xx), which holds the Activity. Usually we immediately associate it with something like this: If xx is not released, the Activity object cannot be released when the Activity is destroyed because it is held by XX. So most of the time we need removeObserver(xx) in activity.ondestroy ().

Let’s look at getLifecycle().addobServer (xx) and see if this situation requires active removal of the Observer. The crux of the matter is who owns xx. As can be seen from the previous analysis, XX is encapsulated as an ObserverWithState object and finally stored in Map. And the Map is:

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

It is a member variable of LifecycleRegistry, and the LifecycleRegistry object is a member variable of ComponentActivity. The end result: Map is a member variable of LifeActivity. When the Activity is destroyed, the Map is destroyed and the Map no longer holds an Observer. Therefore, it is concluded that:

No need to call getLifecycle().removeObserver(observer);

The essence of a memory leak is that a long-life object holds a reference to a short-life object, making the short-life object unable to be released.

5, summary

This article does not focus on the transition between Lifecycle.State and Lifecycle.Event. And understand its design principle. Lifecycle is the foundation of LiveData and the benefits of LiveData will be analyzed next.

This article is based on: implementation ‘androidx. Appcompat: appcompat: 1.4.1’

Lifecycle source code testing

If you like, please like, pay attention to your encouragement is my motivation to move forward

Continue to update, with me step by step system, in-depth study of Android

4, View Measure/Layout/Draw 5, Android events distribution of full service 6, Android invalidate postInvalidate/requestLayout thoroughly clarify 7, how do you determine the Android Window size/onMeasure () to be executed multiple times Android event driver Handler-message-Looper 9, Android keyboard in one move 10, Android coordinates completely clear 11, Android Activity/Window/View background Android IPC series 14, Android Storage series 15, Java concurrent series no longer confusion 16, Java thread pool series 17, Android Jetpack Android Jetpack is easy to learn and easy to understand