Jetpack source code analysis -- managing life cycle with Lifecycles

Posted by ciaran on Tue, 11 Jan 2022 08:40:26 +0100

1. Background

In the last article, I introduced Navigation in the Jetpack component and analyzed its source code. I believe I have a certain understanding of it after reading it. In this article, we will introduce the use and source code of Lifecycles. Before reading the previous article, you can have a look:

Series of articles:

1. Jetpack source code analysis - you will know what Navigation is after reading it?

2. Jetpack source code analysis - why does Navigation switch fragments to redraw?

2. Foundation

2.1 introduction

Lifecycles is a class that holds information about component lifecycle states (such as Activity and Fragment) and allows other objects to observe this state. It can help us easily manage the life cycle of Activity and Fragment.

Lifecycle components track the lifecycle of their associated components through two enumeration classes:

2.2 basic use

In our daily development, we often need to manually manage the release of resources in the life cycle method of Activity or Fragment. For example, when we do custom camera scanning, camera related resources need to be released and previewed manually; Or when we use MVP mode to develop, the creation and destruction of MVP also need us to operate in the life cycle method.

Through the lifecycle components, we can use: We can define an Observer to implement lifecycle Observer and observe it in Activity or Fragment:

/**
 * created by ${Hankkin}
 * on 2019-06-10
 */

class MyObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        Log.e(javaClass.name, "-------onStart")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        Log.e(javaClass.name, "-------onCreate")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        Log.e(javaClass.name, "-------onResume")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        Log.e(javaClass.name, "-------onPause")
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onStop() {
        Log.e(javaClass.name, "-------onStop")
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        Log.e(javaClass.name, "-------onDestroy")
    }

}

Here is the Activity:

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


        lifecycle.addObserver(MyObserver())
        Log.e(javaClass.name, "-------onCreate")

    }

    override fun onStart() {
        super.onStart()
        Log.e(javaClass.name, "-------onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.e(javaClass.name, "-------onResume")
    }

    override fun onPause() {
        super.onPause()
        Log.e(javaClass.name, "-------onPause")
    }

    override fun onStop() {
        super.onStop()
        Log.e(javaClass.name, "-------onStop")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e(javaClass.name, "-------onDestroy")
    }
}

Start the Activity, and we can see the print log in the console:

MainActivity: -------onCreate
MyObserver: -------onCreate
MainActivity: -------onStart
MyObserver: -------onStart
MainActivity: -------onResume
MyObserver: -------onResume
......

Through console printing, we can see that the logs of our observer Activity and the observed are printed. How is it realized?

3. Source code analysis

Through the code, we can see that the Lifecycle components are implemented through the observer mode. Next, we analyze the implementation principle in detail. We find that the Lifecycle can be obtained directly through the getLifecycle() method in Activity and Fragment, so let's start from here:

3.1 getLifecycle()

We click in and find that the lifecycle owner interface is implemented in the ComponentActivity, the getLifecycle() method is declared in the lifecycle owner interface, and the mlicycleregistry is directly returned in the ComponentActivity:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    ......
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

What is Lifecycle registry? Originally, it inherited Lifecycle

public class LifecycleRegistry extends Lifecycle

3.2 Lifecycle and lifecycle registry

Let's look at the Lifecycle class:

public abstract class Lifecycle {

        //Register LifecycleObserver (such as Presenter)
        public abstract void addObserver(@NonNull LifecycleObserver observer);
        //Remove LifecycleObserver 
        public abstract void removeObserver(@NonNull LifecycleObserver observer);
        //Get current status
        public abstract State getCurrentState();

        public enum Event {
            ON_CREATE,
            ON_START,
            ON_RESUME,
            ON_PAUSE,
            ON_STOP,
            ON_DESTROY,
            ON_ANY
        }
        
       public enum State {
            DESTROYED,
            INITIALIZED,
            CREATED,
            STARTED,
            RESUMED;

            public boolean isAtLeast(@NonNull State state) {
                return compareTo(state) >= 0;
            }
       }
}

Lifecycle is an enumeration class that declares some abstract methods and two states. See lifecycle registry for specific implementation:

public class LifecycleRegistry extends Lifecycle {

// LifecycleObserver Map. Each Observer has a State
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();
    // Current status
    private State mState;
    // The lifecycle owner, ComponentActivity, inherits the lifecycle owner
    private final WeakReference<LifecycleOwner> mLifecycleOwner;

    //Modify State value
    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;
    }

    /**
    * Add a lifecycle Observer and distribute the previous status to the Observer. For example, we register the Observer after onResume,
    * The Observer can still receive ON_CREATE event
    */
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        //New observer with status
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
        ......
        // For example, the initial state of Observer is INITIALIZED and the current state is RESUMED. You need to set the value between INITIALIZED and RESUMED
        // Distribute all events to Observer
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            targetState = calculateTargetState(observer);
        }
        ......
}

/**
     * Synchronize Observer status and distribute events
     */
    private void sync() {
        LifecycleOwner lfecycleOwner = 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;
            // In State, the State value is increased from degraded-initialized-created-started-resumed
            // If the current status value is less than the Observer status value, notify the Observer to reduce the status value until it is equal to the current status value
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            // If the current status value > Observer status value, you need to notify Observer to increase the status value until it is equal to the current status value
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

    /**
     * Pass the event forward, corresponding to initialized - > resumed in the figure
     * Increase the status value of Observer until the status value is equal to the current status value
     */
    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();
            while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                pushParentState(observer.mState);
                // Distribution status change event
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
                popParentState();
            }
        }
    }

    /**
     * The event is passed back, corresponding to the resumed - > destroyed in the figure
     * Decrease the status value of Observer until the status value is equal to the current status value
     */
    private void backwardPass(LifecycleOwner lifecycleOwner) {
        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);
                // Distribution status change event
                pushParentState(getStateAfter(event));
                observer.dispatchEvent(lifecycleOwner, event);
                popParentState();
            }
        }
    }

After reading the LifecycleRegistry code, the comments are clear. The basic function is to add observers, respond to life cycle events, and distribute life cycle events.

3.3 ReportFragment

Next, we continue to analyze ComponentActivity. We found a familiar ReportFragment in the onCreate() declaration cycle. I used to encounter this fragment when optimizing memory leakage. This class is often reported in leakcanary, so let's take a look at ReportFragment injectIfNeededIn(this); What the hell did you do?

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class ReportFragment extends Fragment {
    private static final String REPORT_FRAGMENT_TAG = "androidx.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();
        }
    }
    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;
        }

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

Looking at the source code, we find that ReportFragment handles distribution events in each life cycle by calling getlifecycle() Handle lifecycle event (event) for lifecycle distribution. This means that a ReportFragment without a page is added to the ComponentActivity. When the life cycle of the Activity changes, you can call LifecycleRegistry The handlellifecycle event () method notifies LifecycleRegistry to change the state. LifecycleRegistry internally calls moveToState() to change the state and calls each lifecycleobserver The onstatechange() method notifies of lifecycle changes.

By looking at the ReportFragment call, we find that there are two other classes that call it, one is lifecycle dispatcher and the other is processlifecycle owner. What exactly do these two classes do?

[external chain picture transfer failed (img-kmu4o9el-1562754821909)( http://psv0rasgi.bkt.clouddn.com/jetpack/_image/2019-06-10/ Screenshot June 11, 2019 2.19.20 PM (2) png#align=left&display=inline&height=324&originHeight=648&originWidth=1112&status=done&width=556)]

3.4 LifecycleDispatcher

class LifecycleDispatcher {

    private static AtomicBoolean sInitialized = new AtomicBoolean(false);

    static void init(Context context) {
        if (sInitialized.getAndSet(true)) {
            return;
        }
        ((Application) context.getApplicationContext())
                .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
    }

    @SuppressWarnings("WeakerAccess")
    @VisibleForTesting
    static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            ReportFragment.injectIfNeededIn(activity);
        }

        @Override
        public void onActivityStopped(Activity activity) {
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }
    }

    private LifecycleDispatcher() {
    }
}

We check the source code and find that in the init() method, the dispatcher Activity callback is registered through the Application, and the ReportFragment is injected into the Activity in onActivityCreated.

3.5 ProcessLifecycleOwner

public class ProcessLifecycleOwner implements LifecycleOwner {

       private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

    private Runnable mDelayedPauseRunnable = new Runnable() {
        @Override
        public void run() {
            dispatchPauseIfNeeded();
            dispatchStopIfNeeded();
        }
    };

    private ActivityInitializationListener mInitializationListener =
            new ActivityInitializationListener() {
                @Override
                public void onCreate() {
                }

                @Override
                public void onStart() {
                    activityStarted();
                }

                @Override
                public void onResume() {
                    activityResumed();
                }
            };

    private static final ProcessLifecycleOwner sInstance = new ProcessLifecycleOwner();

   
    public static LifecycleOwner get() {
        return sInstance;
    }

    static void init(Context context) {
        sInstance.attach(context);
    }

    void activityStarted() {
        mStartedCounter++;
        if (mStartedCounter == 1 && mStopSent) {
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
            mStopSent = false;
        }
    }

    void activityResumed() {
        mResumedCounter++;
        if (mResumedCounter == 1) {
            if (mPauseSent) {
                mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
                mPauseSent = false;
            } else {
                mHandler.removeCallbacks(mDelayedPauseRunnable);
            }
        }
    }

   ......
    private void dispatchStopIfNeeded() {
        if (mStartedCounter == 0 && mPauseSent) {
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
            mStopSent = true;
        }
    }

    private ProcessLifecycleOwner() {
    }
    //Listen to the Application lifecycle and distribute it to the Activity
    void attach(Context context) {
        mHandler = new Handler();
        mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        Application app = (Application) context.getApplicationContext();
        app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                ReportFragment.get(activity).setProcessListener(mInitializationListener);
            }

            @Override
            public void onActivityPaused(Activity activity) {
                activityPaused();
            }

            @Override
            public void onActivityStopped(Activity activity) {
                activityStopped();
            }
        });
    }
}

According to the official notes, we can learn that:

  • Processlifecycle owner is used to listen to the Application lifecycle, so it will only distribute on once_ Create event, and on will not be distributed_ Destroy event.
  • Processlifecycle owner adopts handle in onResume and onStop methods of Activity The postdelayed () method is used to handle that events will not be sent during Activity reconstruction, such as horizontal and vertical screen switching.
  • Processlifecycle owner is generally used to determine whether an application is in the foreground or background. However, due to the use of handle Postdelayed(), so this judgment is not immediate and has a default delay of 700ms.
  • Like lifecycle dispatcher, processlifecycle owner registers application Registeractivitylifecyclecallbacks to listen for the Activity's lifecycle callbacks and add reportfragments to each Activity.

After looking at the two classes, we find that their entries are init(), so let's see who called them?

3.6 ProcessLifecycleOwnerInitializer

public class ProcessLifecycleOwnerInitializer extends ContentProvider {
    @Override
    public boolean onCreate() {
        LifecycleDispatcher.init(getContext());
        ProcessLifecycleOwner.init(getContext());
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, String[] strings, String s, String[] strings1,
            String s1) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, String s, String[] strings) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, ContentValues contentValues, String s, String[] strings) {
        return 0;
    }
}

If so, initialize these two in onCreate() of processlifecycle ownerinitializer to see that the class name can be translated into_ Process lifecycle initialization, Here, we can't find the caller or user for this class, so we have to Baidu and find that some people say this class is in androidmanifest XML, in the process of building APK, AS will add AndroidManifest.xml of multiple modules XML are merged together, so check the build directory. The specific path is build/intermediates/bundle_manifest/debug/processDebugManifest/bundle-manifest/AndroidManifest.xml, if it's really in it:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hankkin.reading_aac"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="28" />

    <application
        android:appComponentFactory="androidx.core.app.CoreComponentFactory"
        android:debuggable="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:testOnly="true"
        android:theme="@style/AppTheme" >
        <activity android:name="com.hankkin.reading_aac.ui.LoginActivity" >
        </activity>
        <activity android:name="com.hankkin.reading_aac.MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
            android:authorities="com.hankkin.reading_aac.lifecycle-process"
            android:exported="false"
            android:multiprocess="true" />
    </application>

</manifest>

Here, the whole Lifecycle initialization process is over.

4. Summary

After the above source code analysis, we can roughly divide the entire Lifecycle component into three parts:

4.1 Lifecycle initialization

Through in manifest Statement in provider,`ProcessLifecycleOwnerInitializer`register Activity and fragment.Call back and listen to the declaration cycle of Activity Add a blank`ReportFragment`,Use it as an event distribution for the lifecycle. And when Activity and Fragment When the lifecycle state changes, it passes LifecycleRegistryOwner To handle changes in lifecycle state.

4.2 Lifecycle status change and status distribution

stay`ReportFragment`Call in`LifecycleRegister.handleLifecycleEvent(Lifecycle.Event)`,adopt**Get the next status corresponding to the event**as well as**Change the current state to the next state**,Synchronous distribution events; Finally, the lifecycle states of each observer are moved to the correct state in turn.

You can view the following sequence diagram:

4.3 Lifecycle analysis

The methods in our declared MyObserver are annotated. Check onllifecycle event:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnLifecycleEvent {
    Lifecycle.Event value();
}

Annotation modified methods will be obtained through reflection and saved in the ClassesInfoCache. Then, when the life cycle changes, find the method corresponding to the Event and call the method through reflection.

5. Reference link:

https://juejin.im/post/5cd81634e51d453af7192b87#heading-10

https://yuqirong.me/2018/07/15/Android%20Architecture%20Component%E4%B9%8BLifecycle%E8%A7%A3%E6%9E%90/