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