preface
The previous articles are to lay the foundation for Jetpack. This article will officially enter the analysis of various components of Jetpack from Lifecycle.
Through this article, you will learn:
1. Why Lifecycle?
2. How is Lifecycle used?
3. How does Lifecycle perceive the Lifecycle
4. Lifecycle memory leak?
5. Summary
1. Why Lifecycle?
Start of life cycle
Common components with life cycle in Android, such as Activity, Fragment, Service, etc., of which Activity and Fragment are the most common, and the life cycle of Fragment depends on Activity, so it's no big deal to master the life cycle of Activity.
For the story of the ups and downs of the Activity life cycle, please move to:
Detailed explanation and monitoring of Android Activity life cycle
Application of life cycle
Bronze player
Take a simple example: when you enter an Activity (get focus), you need a network request. When the Activity exits (lose focus), you stop the network request. The simplest way is as follows:
@Override protected void onResume() { super.onResume(); NetRequest.startRequest(); } @Override protected void onPause() { super.onPause(); NetRequest.stopRequest(); }
Rewrite the onResume() method. When this method is called, it indicates that the Activity has obtained the focus, and the page will be displayed. At this time, the network request can be made to pull data.
Rewrite the onPause() method. When the method is called, it means that the Activity has lost focus. At this time, there is no need to request the network.
There seems to be no problem, but think about it carefully: for example, when playing a video, you also need to play it in the onResume() method, pause it in the onPause() method, and then, for example, database operation. At this time, many codes are stacked in onResume(), onPause(), making the Activity very bloated.
Silver player
You say it doesn't matter. I have MVP architecture and can use Presenter to encapsulate these business logic.
Declare Presenter class: lifecycle Presenter
public class LifecyclePresenter implements ILifecycle{ @Override public void onResume() { NetRequest.startRequest(); } @Override public void onPause() { NetRequest.stopRequest(); } }
This class implements the interface: ILifecycle, and the method declared by this interface is consistent with the Activity life cycle:
interface ILifecycle { void onCreate(); void onStart(); void onResume(); void onPause(); void onStop(); void onDestroy(); }
OK, finally, monitor the changes in the life cycle in the Activity, and then call different methods of LifecyclePresenter:
@Override protected void onResume() { super.onResume(); lifecyclePresenter.onResume(); } @Override protected void onPause() { super.onPause(); lifecyclePresenter.onPause(); }
In this way, there will be other business logic in the future. You only need to add it in the corresponding method of lifecycle presenter to achieve the effect of reducing the burden on the Activity.
Gold player
Although only one line of code is added to each method in the Activity life cycle, considering the separation of UI and logic, it is best not to couple the two. For example, in the division of labor, some students are responsible for the UI, so they may not care when to start / end the network request. These are written by the students responsible for the specific business logic. How to achieve it?
Remember when analyzing the Activity life cycle:
Activity provides the registeractivitylifecycle callbacks (callback) method, which will be called when the activity lifecycle changes. So we can monitor the life cycle changes here, and then 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(); } }); } }
The Activity passed in is the Activity that wants to listen to the 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(); } }); } }
Change the Presenter to: lifecycle presenterv2.
At this point, the Activity only needs to call:
//this indicates the Activity that needs to be monitored at present LifecyclePresenterV2 lifecyclePresenterV2 = new LifecyclePresenterV2(this);
It can be seen that:
There is no need to rewrite the callback methods of each life cycle in the Activity. Just one line of code is needed to put these logic into a separate business layer for processing. The life cycle is bound to the specific business. It depends on how the business needs are linked with the life cycle.
If the Activity is changed later, there is no need to change the business of the logical layer.
Everything seems to be all right? No, look carefully. The registerActivityLifecycleCallbacks() method call has version restrictions: @ RequiresApi(api = Build.VERSION_CODES.Q)
This means that the API must be more than Android 10(29) to call, which has great limitations.
Introduction of Lifecycle
From the above analysis, we can perceive that the interaction scenarios between life cycle and business are very rich, and we really need a set of tools to help us simplify the interaction process.
Google said to have Lifecycle, so it has Lifecycle.
At the outset: the source code of Lifecycle is not complex. It mainly does three things:
1. It provides an interface for the outside world to monitor a certain stage in the life cycle of interest (onResume, onPause, onDestroy, etc.), and the outside world is incarnated as an observer at this time.
2. Listen to the Activity life cycle somewhere. At this time, the Activity is the observed.
3. Inform the observer of the life cycle.
2. How is Lifecycle used?
Add observer
From the three things of Lifecycle, if the outside world wants to monitor the changes of the life cycle, it only needs to add an observation interface and process the corresponding life cycle in the callback method of the interface.
There are two different ways:
###1. Annotate observations
Previous versions of Lifecycle used annotations to simplify the observer in order to minimize rewriting methods in the interface.
//Implementation of annotation class MyObserver7 implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) void onPause() { Log.d(TAG, "onPause"); } }
Here we only focus on onPause. If you want to monitor other status changes, you only need to add comments on the corresponding status.
Then listen in the Activity:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle); getLifecycle().addObserver(new MyObserver7()); }
When the Activity loses focus, it will call the onPause() method in MyObserver7.
It can be seen that you only need to add observers in the Activity.
###2. Interface mode processing observation results
The new version of Lifecycle discards the annotation observation mode and uses the interface instead. If you use Java 8 or turn on Java 8 features, it is recommended to use the interface mode.
//Java 8 mode 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()); }
It can be seen that 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); }
The DefaultLifecycleObserver interface implements all methods of FullLifecycleObserver by default
@Override default void onCreate(@NonNull LifecycleOwner owner) { } ....
It can be seen that a new feature of Java 8 is used: default modifies the interface method.
Therefore, when we implement the DefaultLifecycleObserver interface, we only need to rewrite the interface corresponding to the concerned state.
3. How does Lifecycle perceive the Lifecycle
To sum up, we can easily perceive the changes of the Activity life cycle through Lifecycle. In the previous part, we also analyze how to encapsulate the life cycle step by step. Unfortunately, we encounter the problem of the version limit of registeractivitylifecycle callbacks. Next, we will explore how Lifecycle can bypass the limit.
Step 1: register observers
LifecycleRegistry
Both the interface and annotation methods use getLifecycle(). This method returns the Lifecycle object, and Lifecycle is an abstract class. getLifecycle() returns the object of Lifecycle subclass: LifecycleRegistry.
#ComponentActivity.java private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this); public Lifecycle getLifecycle() { return mLifecycleRegistry; }
When a custom Activity inherits from AppCompatActivity, and ComponentActivity is the parent class of AppCompatActivity, therefore, when a custom Activity calls getLifecycle(), it returns the mlife cycleregistry object.
The mllifecycle owner 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 in observer and construct observer withstate LifecycleRegistry.ObserverWithState statefulObserver = new LifecycleRegistry.ObserverWithState(observer, initialState); //Add the ObserverWithState to the map LifecycleRegistry.ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); ... }
The key is the ObserverWithState:
#LifecycleRegistry.java static class ObserverWithState { //Lifecycle state Lifecycle.State mState; //Observer LifecycleEventObserver mLifecycleObserver; ObserverWithState(LifecycleObserver observer, Lifecycle.State initialState) { //Encapsulate observer mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer); mState = initialState; } void dispatchEvent(LifecycleOwner owner, Lifecycle.Event event) { //Distribute events and turn event into state Lifecycle.State newState = event.getTargetState(); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; } }
Look at lifecycle lifecycleEventObserver:
#Lifecycling.java static LifecycleEventObserver lifecycleEventObserver(Object object) { //Interface mode boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver; ... if (isFullLifecycleObserver) { //If the observer is in interface mode, return directly return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null); } //Process the annotation, record the annotation, and get it directly from the map next time final Class<?> klass = object.getClass(); int type = getObserverConstructorType(klass); ... return new ReflectiveGenericLifecycleObserver(object); }
addObserver() focuses on adding the Observer to the Map after some column encapsulation.
Obviously, we will think that when the life cycle changes, the observer will be taken out of the Map and notified.
Step 2: life cycle change - notify the observer
Android10 (inclusive) and above processing methods
The best way to understand how Lifecycle informs the observer is to view its call stack through a breakpoint.
Taking the interface processing method as an example, when the observer is called, its call stack is as follows:
Notice activity 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 callback method ((Application.ActivityLifecycleCallbacks) callbacks[i]) .onActivityPostStarted(this); } } ... }
The listener here is through activity Registeractivitylifecycle callbacks (callback).
The callback is: reportfragment Lifecyclecallbacks object, which is registered in:
#ReportFragment.java public static void injectIfNeededIn(Activity activity) { if (Build.VERSION.SDK_INT >= 29) { //If you are above Android 10, you can register activitylifecycle callbacks directly ReportFragment.LifecycleCallbacks.registerIn(activity); } //Add an empty Fragment to the Activity 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(); } }
The call time of injectifneedin is in activity Oncreate().
Well, now we know:
When an Activity is created, monitor the change of Activity status through ReportFragment.
According to different system versions, ReportFragment can be monitored in two ways:
1. Devices above Android 10 (inclusive) are monitored through registerActivityLifecycleCallbacks().
2. Below Android 10, it is monitored through Fragment.
So far, Lifecycle only listens to the status of Activity and needs to distribute the status.
Take the processing method of Android 10 as an example:
#ReportFragment.java static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) { ... if (activity instanceof LifecycleOwner) { //Get Lifecycle, that is, Lifecycle registry Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle(); if (lifecycle instanceof LifecycleRegistry) { //Distribution event ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); } } }
The final Event is still handled by LifecycleRegistry. In LifecycleRegistry, the corresponding encapsulated observer is found in the Map according to the transformation of Event and State, and the observer registered in Activity is finally notified. So far, a notification of life cycle State change is completed.
Android 10 the following processing methods
We know that when a Fragment is associated with an Activity, its life cycle is linked with the Activity. Please move to: What does Android Fragment want you to do?
Therefore, when the life cycle of an Activity changes, a Fragment method will be called. Take onStart() status as an example:
#ReportFragment.java @Override public void onStart() { super.onStart(); dispatchStart(mProcessListener); //Distribution event dispatch(Lifecycle.Event.ON_START); } private void dispatch(@NonNull Lifecycle.Event event) { if (Build.VERSION.SDK_INT < 29) { //Only when Android is below 10 dispatch(getActivity(), event); } }
At this point, we know how Lifecycle handles the version limitation of registerActivityLifecycleCallbacks(): that is, it shields the upper callers from the details of monitoring the changes of Activity life cycle through ReportFragment. Use registerActivityLifecycleCallbacks() on Android 10 and above, and add empty fragments under it to the Activity.
Lifecycle aware lifecycle summary
It is shown as follows:
Green part:
Lifecycle monitors Activity lifecycle changes.
Blue part:
The outside world registers observers through Lifecycle.
Red part:
Lifecycle monitors changes in the lifecycle and notifies the observer.
4. Lifecycle memory leak?
Add the following code to the Activity (assuming it is customized as LifeActivity) onCreate() to monitor the Activity life cycle:
getLifecycle().addObserver(new DefaultLifecycleObserver() { @Override public void onCreate(@NonNull @org.jetbrains.annotations.NotNull LifecycleOwner owner) { } });
Here's the question: do you need to be in activity Remove the observer from ondestroy()?
We know that the anonymous inner class holds the external class reference, addObserver(xx). This xx object holds the Activity. Generally speaking, when we see this writing, we are immediately associated with it: if xx is not released, when the Activity is destroyed, the Activity object cannot be released because it is held by xx.
So most of the time we need to be in activity removeObserver(xx) in ondestroy().
Next, let's take a look at getlifecycle() Addobserver (xx) whether the observer needs to be removed actively in this case. The key question is who owns xx.
According to the previous analysis, xx is encapsulated as an ObserverWithState object and finally stored in the Map. The Map is:
#LifecycleRegistry.java private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();
It is the member variable of LifecycleRegistry, and the LifecycleRegistry object is the member variable of ComponentActivity. The final result: Map is the member variable of LifeActivity.
When the Activity is destroyed, the Map will be destroyed and the Map will no longer hold the Observer.
Therefore, it is concluded that:
There is no need to call getlifecycle() removeObserver(observer);
The essence of memory leakage is that long-lived objects hold references to short-lived objects, which makes short-lived objects unable to be released.
5. Summary
This article does not focus on Lifecycle And Lifecycle.State The transformation between events focuses on why Lifecycle is needed and how Lifecycle perceives the Lifecycle, hoping to naturally introduce Lifecycle and understand its design principle.
Lifecycle is the foundation of LiveData. Next, we will analyze the wonderful use of LiveData.
This article is based on: implementation 'Android X appcompat:appcompat:1.4.1’