1, Introduction to Android Jetpack
1.1 what is jetpack
The official definition is as follows:
Jetpack is a suite composed of multiple libraries, which can help developers follow best practices, reduce template code, and write code that can run consistently in various Android versions and devices, so that developers can focus on writing important code.
JetPack is more of a concept and attitude. It is a collection of SDK / development specifications that are not included in the Android Framework SDK developed by Google, but are necessary / recommended for Android development. It is equivalent to Google reorganizing its Android ecosystem and establishing the general direction of Android development in the future.
Using Jetpack has the following benefits:
- Following best practices, Android Jetpack components are built with the latest design methods, have backward compatibility, and can reduce crashes and memory leaks.
- By eliminating boilerplate code, Android Jetpack can manage a variety of cumbersome activities (such as background tasks, navigation and Lifecycle Management), so that you can focus on building excellent applications.
- Reduce inconsistencies, and these libraries work in a consistent manner across Android versions and devices, helping you reduce complexity.
Jetpack originally means jet backpack. Android goes straight to the sky after carrying jetpack, which is very vivid~
In other words, Jetpack is a tool set to help developers develop applications efficiently. So what does this tool include?
1.2 Jetpack classification
The classification is as follows:
The Android Jetpack component covers the following four aspects: Architecture, Foundation, Behavior, and UI.
The real essence is Architecture, the full name is Android Architecture Component (AAC), that is, Android architecture component.
It includes successful Lifecycle, LiveData and ViewModel. It is also the best framework tool for us to use MVVM mode. It can be used in combination or alone.
The above is basically the introduction of the official website. Our main goal is to master the components of AAC, deeply understand and then apply it to the MVVM architecture.
For example, the focus of learning Jetpack is AAC. This article starts from the basic Lifecycle.
2, Lifecycle
Lifecycle, as its name suggests, is used to help developers manage the life cycle of activities and fragments. It is the basis of LiveData and ViewModel. Here's why and how to use lifecycle.
2.1 before lifecycle
There is an example in the official document to illustrate how to use Lifecycle management before using Lifecycle:
Suppose we have an Activity that displays the location of the device on the screen. Common implementations may be as follows:
class MyLocationListener { public MyLocationListener(Context context, Callback callback) { // ... } void start() { // Connection system location service } void stop() { // Disconnect system location service } } class MyActivity extends AppCompatActivity { private MyLocationListener myLocationListener; @Override public void onCreate(...) { myLocationListener = new MyLocationListener(this, (location) -> { // Update UI }); } @Override public void onStart() { super.onStart(); myLocationListener.start(); // Manage other components that need to respond to the activity lifecycle } @Override public void onStop() { super.onStop(); myLocationListener.stop(); // Manage other components that need to respond to the activity lifecycle } }
Although this example looks ok, in a real application, there will eventually be too many calls to the management interface and other components in response to the current state of the life cycle. Managing multiple components places a lot of code in lifecycle methods such as onStart() and onStop(), which makes them difficult to maintain.
In addition, there is no guarantee that the component will start mylocationlistener before the Activity or Fragment stops. This is especially true when we need to perform long-running operations, such as some configuration check in onStart(). In this case, the onStop() method of myLocationListener is called before onStart (), which makes the component remaining longer than the time required, resulting in internal leakage. As follows:
class MyActivity extends AppCompatActivity { private MyLocationListener myLocationListener; public void onCreate(...) { myLocationListener = new MyLocationListener(this, location -> { // Update UI }); } @Override public void onStart() { super.onStart(); Util.checkUserStatus(result -> { //If checkUserStatus takes a long time and calls back after the activity stops, then the stop() method cannot be used after myLocationListener is started, //Because myLocationListener holds activity, it will cause memory leakage. if (result) { myLocationListener.start(); } }); } @Override public void onStop() { super.onStop(); myLocationListener.stop(); } }
There are two problem points:
- There is a lot of code to manage components in the life cycle of activity, which is difficult to maintain.
- There is no guarantee that the component will not start after the Activity/Fragment is stopped
Lifecycle library can solve these problems in an elastic and isolated manner.
2.2 use of lifecycle
Lifecycle is a library and also contains a class like lifecycle. Lifecycle class is used to store information about the lifecycle state of components (such as Activity or Fragment) and allow other objects to observe this state.
2.2.1 introducing dependencies
1. Non Android X project introduction:
implementation "android.arch.lifecycle:extensions:1.1.1"
Adding this sentence depends on the following Library:
2. Android X project introduction:
If the project already depends on Android X:
implementation 'androidx.appcompat:appcompat:1.2.0'
Then we can use the Lifecycle library, because appcompat depends on Android x.fragment, while Android x.fragment depends on ViewModel and LiveData, and LiveData internally depends on Lifecycle.
If you want to introduce dependencies separately, see the following:
Add google() code base to build.gradle in the root directory of the project, and then introduce dependencies to build.gradle of app. The official dependencies are as follows:
//build.gradle in the root directory repositories { google() ... } //build.gradle of app dependencies { def lifecycle_version = "2.2.0" def arch_version = "2.1.0" // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // LiveData implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version" // Only Lifecycles (without ViewModel or LiveData) implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" // Saved state module for ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" // lifecycle annotation processor annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // Replace - if you use Java 8, replace the lifecycle compiler above with this one implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" //The following are introduced as needed // Optional - help implement the lifecycle owner of the Service implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version" // Optional - processlifecycle owner provides a lifecycle for the entire app process implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" // Optional - ReactiveStreams support for LiveData implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // Optional - Test helpers for LiveData testImplementation "androidx.arch.core:core-testing:$arch_version" }
It seems that there are many. In fact, if you only use Lifecycle, you only need to introduce Lifecycle runtime. However, they are usually used together with ViewModel and LiveData, so Lifecycle ViewModel and Lifecycle LiveData will also be introduced.
In addition, lifecycle process provides a lifecycle for the entire app process, which will also be mentioned in the meeting.
2.2.2 application method
Lifecycle is simple to use:
- 1. The Lifecycle owner uses getLifecycle() to obtain the Lifecycle instance, and then uses addObserve() to add the observer;
- 2. The observer implements LifecycleObserver. The onllifecycle event annotation is used to focus on the corresponding life cycle. When the life cycle is triggered, the corresponding method will be executed;
2.2.2.1 basic use
In Activity (or Fragment), the general usage is as follows:
public class LifecycleTestActivity extends AppCompatActivity { private String TAG = "Lifecycle_Test"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle_test); //Lifecycle lifecycle getLifecycle().addObserver(new MyObserver()); Log.i(TAG, "onCreate: "); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "onResume: "); } @Override protected void onPause() { super.onPause(); Log.i(TAG, "onPause: "); } }
Activity (or Fragment) is the owner of the life cycle. The life cycle object is obtained through the getLifecycle() method. The life cycle object uses the addObserver method to add an observer to itself, that is, the MyObserver object. When the Lifecycle changes, MyObserver can perceive it.
How does MyObserver use the lifecycle? Take a look at the implementation of MyObserver:
public class MyObserver implements LifecycleObserver { private String TAG = "Lifecycle_Test"; @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME) public void connect(){ Log.i(TAG, "connect: "); } @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE) public void disConnect(){ Log.i(TAG, "disConnect: "); } }
Firstly, MyObserver implements the interface LifecycleObserver, which is used to mark a class as a lifecycle observer. Then @ onllifecycle event annotation is added to connectListener() and disconnectListener(), and the value is lifecycle.event.on respectively_ RESUME,Lifecycle.Event.ON_PAUSE, the effect is: connectListener() will be on_ When resume is executed, disconnectListener() will be on_ Execute when pause.
We open lifecycle test activity and exit. The log is printed as follows:
2020-11-09 17:25:40.601 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onCreate: 2020-11-09 17:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onResume: 2020-11-09 17:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: connect: 2020-11-09 17:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: disConnect: 2020-11-09 17:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onPause:
It can be seen that the method of MyObserver is indeed called when the corresponding concerned life cycle is triggered. Of course, the value in the annotation can also be written as any other life cycle you are concerned about, such as Lifecycle.Event.ON_DESTROY.
2.2.2.2 use in MVP architecture
In the MVP architecture, the presenter can be used as an observer:
public class LifecycleTestActivity extends AppCompatActivity implements IView { private String TAG = "Lifecycle_Test"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle_test); //Lifecycle lifecycle // getLifecycle().addObserver(new MyObserver()); //Using Lifecycle in MVP getLifecycle().addObserver(new MyPresenter(this)); Log.i(TAG, "onCreate: "); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "onResume: "); } @Override protected void onPause() { super.onPause(); Log.i(TAG, "onPause: "); } @Override public void showView() {} @Override public void hideView() {} } //Presenter class MyPresenter implements LifecycleObserver { private static final String TAG = "Lifecycle_Test"; private final IView mView; public MyPresenter(IView view) {mView = view;} @OnLifecycleEvent(value = Lifecycle.Event.ON_START) private void getDataOnStart(LifecycleOwner owner){ Log.i(TAG, "getDataOnStart: "); Util.checkUserStatus(result -> { //checkUserStatus is a time-consuming operation. Check the current lifecycle status after callback if (owner.getLifecycle().getCurrentState().isAtLeast(STARTED)) { start(); mView.showView(); } }); } @OnLifecycleEvent(value = Lifecycle.Event.ON_STOP) private void hideDataOnStop(){ Log.i(TAG, "hideDataOnStop: "); stop(); mView.hideView(); } } //IView interface IView { void showView(); void hideView(); }
Here, let the Presenter implement the LifecycleObserver interface, annotate the life cycle to be triggered on the method, and finally add it to the Lifecycle as an observer in the Activity.
What are the benefits of doing so? When the Activity lifecycle changes, MyPresenter can sense and execute the method without calling MyPresenter in multiple lifecycle methods of MainActivity.
- All method call operations are managed by the component itself: the Presenter class automatically senses the life cycle. If you need to use this Presenter in other activities / fragments, you just need to add it as an observer.
- Let each component store its own logic, reduce the code in Activity/Fragment, and make it easier to manage;
——The first problem mentioned above has been solved.
In addition, it is noted that after the time-consuming verification callback in getDataOnStart(), the current life cycle state is checked: the start() method will not be executed until it is at least in the STARTED state, that is, it is guaranteed that the start() method will not be executed after the Activity stops;
——The second problem mentioned above has also been solved.
2.2.3 customize lifecycle owner
When you call getLifecycle() in Activity, you can get the Lifecycle instance. Where is getLifecycle() defined? Interface LifecycleOwner, Gu mingsiyi, lifecycle owner:
/** * Lifecycle owner * Lifecycle events can be used by custom components to handle changes in lifecycle events without writing any code in activity / fragment */ public interface LifecycleOwner { @NonNull Lifecycle getLifecycle(); }
Support Library 26.1.0 and above, Android x Fragment and Activity have implemented the lifecycle owner interface, so we can directly use getLifecycle() in the Activity.
If you have a custom class and want to make it a Lifecycle owner, you can use the Lifecycle registry class, which is the implementation class of Lifecycle, but you need to forward events to this class:
public class MyActivity extends Activity implements LifecycleOwner { private LifecycleRegistry lifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public void onStart() { super.onStart(); lifecycleRegistry.markState(Lifecycle.State.STARTED); } @NonNull @Override public Lifecycle getLifecycle() { return lifecycleRegistry; } }
MyActivity implements the lifecycle owner, and getLifecycle() returns the lifecycle registry instance. The lifecycleRegistry instance is created in onCreate, and the markState() method is called in each life cycle to complete the delivery of life cycle events. This completes the customization of LifecycleOwner, that is, MyActivity becomes LifecycleOwner, and then it can be used with the components that implement LifecycleObserver.
In addition, the observer method can accept a parameter lifecycle owner, which can be used to obtain the current state or continue to add observers. If the annotation is ON_ANY can also receive an Event to distinguish which Event it is. As follows:
class TestObserver implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) void onCreated(LifecycleOwner owner) { // owner.getLifecycle().addObserver(anotherObserver); // owner.getLifecycle().getCurrentState(); } @OnLifecycleEvent(Lifecycle.Event.ON_ANY) void onAny(LifecycleOwner owner, Lifecycle.Event event) { // event.name() } }
2.3 Application lifecycle processlifecycle owner
The previous judgment of the App entering the front and background is through the registeractivitylifecycle callbacks (callback) method, and then count with a global variable in the callback, add 1 in onActivityStarted() and subtract 1 in onActivityStopped() to judge the front and rear switching.
Using processlifecycle owner, you can directly obtain the application front and background switching status. (remember to introduce the lifecycle process dependency first)
The usage method is similar to that in Activity, except that processlifecycle owner. Get() is used to obtain processlifecycle owner. The code is as follows:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //Register App lifecycle watcher ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationLifecycleObserver()); } /** * Application Life cycle observation provides the life cycle of the whole application process * * Lifecycle.Event.ON_CREATE It will only be distributed once, Lifecycle.Event.ON_DESTROY will not be distributed. * * When the first Activity enters, processlifecycle owner will dispatch Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME. * Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP, the distribution will be delayed after the last Activit exits. If the activity is destroyed and recreated due to a configuration change, this delay is sufficient to ensure that the processlifecycle owner does not send any events. * * Function: monitor the application to enter the foreground or background */ private static class ApplicationLifecycleObserver implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) private void onAppForeground() { Log.w(TAG, "ApplicationObserver: app moved to foreground"); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) private void onAppBackground() { Log.w(TAG, "ApplicationObserver: app moved to background"); } } }
It's really simple to see, which is almost the same as the Lifecycle usage of the previous Activity, and it's elegant to use processlifecycle owner. The Lifecycle distribution logic is described in the notes.
3, Source code analysis
The use of Lifecycle is very simple. The next step is to analyze the principle and source code of Lifecycle.
We can guess the principle first: when the lifecycle owner (such as Activity) changes the lifecycle state (that is, when the lifecycle method is executed), it traverses the observers and obtains the annotation on each observer's method. If the annotation is @ onllifecycle event and the value is consistent with the lifecycle state, then this method is executed. Is that a reasonable guess? Let's have a look.
3.1 Lifecycle class
Let's take a look at Lifecycle:
public abstract class Lifecycle { //Add observer @MainThread public abstract void addObserver(@NonNull LifecycleObserver observer); //Remove observer @MainThread public abstract void removeObserver(@NonNull LifecycleObserver observer); //Get current status public abstract State getCurrentState(); //Lifecycle event, corresponding to Activity lifecycle method public enum Event { ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY //Can respond to any event } //Lifecycle state. (Event is the Event that enters this state) public enum State { DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; //Judge at least one state public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; } }
Lifecycle uses two main enumerations to track the lifecycle state of its associated components:
- Event, life cycle events, which correspond to Activity/Fragment life cycle methods.
- State, life cycle state, and Event refers to the Event entering a state.
Event trigger timing:
- ON_CREATE,ON_START,ON_ The resume event is distributed after the method corresponding to the lifecycle owner is executed.
- ON_PAUSE,ON_STOP,ON_ The destroy event is distributed before the method call corresponding to the lifecycle owner.
This ensures that the lifecycle owner is in this state.
There is a clear picture on the official website:
3.2 implementation of lifecycle owner by activity
As mentioned earlier, Activity implements lifecycle owner, so getLifecycle() can be used directly. Specifically, in android.Activity.componentactivity:
//androidx.activity.ComponentActivity, some other codes are ignored here. We only look at the life cycle public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner{ ... private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this); ... @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSavedStateRegistryController.performRestore(savedInstanceState); ReportFragment.injectIfNeededIn(this); //Distributing lifecycle events using ReportFragment if (mContentLayoutId != 0) { setContentView(mContentLayoutId); } } @CallSuper @Override protected void onSaveInstanceState(@NonNull Bundle outState) { Lifecycle lifecycle = getLifecycle(); if (lifecycle instanceof LifecycleRegistry) { ((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED); } super.onSaveInstanceState(outState); mSavedStateRegistryController.performSave(outState); } @NonNull @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; } }
Some other codes are ignored here. We only look at Lifecycle.
See that ComponentActivity implements the interface Lifecycle owner and returns the Lifecycle registry instance in getLifecycle(). As mentioned earlier, Lifecycle registry is a concrete implementation of Lifecycle.
Then set the state of mlife cycleregistry to State.CREATED in onSaveInstanceState(), and then why not? Why not deal with it in other life cycle methods? what? It's different from what you guessed. Don't worry, there is a line in onCreate(): reportfragment. Injectifneedin (this);, This is the key.
3.3 life cycle event distribution - ReportFragment
//Fragment s dedicated to distributing lifecycle events public class ReportFragment extends Fragment { public static void injectIfNeededIn(Activity activity) { if (Build.VERSION.SDK_INT >= 29) { //In API 29 and above, you can directly register a callback to obtain the life cycle activity.registerActivityLifecycleCallbacks( new LifecycleCallbacks()); } //Before API29, fragment was used to obtain the life cycle if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) { manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit(); manager.executePendingTransactions(); } } @SuppressWarnings("deprecation") static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) { if (activity instanceof LifecycleRegistryOwner) {//It's abandoned here. Don't look ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event); return; } if (activity instanceof LifecycleOwner) { Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle(); if (lifecycle instanceof LifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);//Use the handlellifecycle event method of LifecycleRegistry to process events } } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); dispatch(Lifecycle.Event.ON_CREATE); } @Override public void onStart() { super.onStart(); dispatch(Lifecycle.Event.ON_START); } @Override public void onResume() { super.onResume(); dispatch(Lifecycle.Event.ON_RESUME); } @Override public void onPause() { super.onPause(); dispatch(Lifecycle.Event.ON_PAUSE); } ...ellipsis onStop,onDestroy private void dispatch(@NonNull Lifecycle.Event event) { if (Build.VERSION.SDK_INT < 29) { dispatch(getActivity(), event); } } //In API 29 and above, use the lifecycle callback static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks { ... @Override public void onActivityPostCreated(@NonNull Activity activity,@Nullable Bundle savedInstanceState) { dispatch(activity, Lifecycle.Event.ON_CREATE); } @Override public void onActivityPostStarted(@NonNull Activity activity) { dispatch(activity, Lifecycle.Event.ON_START); } @Override public void onActivityPostResumed(@NonNull Activity activity) { dispatch(activity, Lifecycle.Event.ON_RESUME); } @Override public void onActivityPrePaused(@NonNull Activity activity) { dispatch(activity, Lifecycle.Event.ON_PAUSE); } ...ellipsis onStop,onDestroy } }
First, the versions of injectifneedin() are distinguished: directly register the lifecycle callback using the registerActivityLifecycleCallbacks of the activity in API 29 and above, and then add a ReportFragment to the current activity. Note that this fragment has no layout.
Then, both the lifecycle methods of LifecycleCallbacks and fragment s finally go to the dispatch (activity, lifecycle. Event) method, which internally uses the handlellifecycle event method of LifecycleRegistry to process events.
The function of ReportFragment is to obtain the life cycle, because the life cycle of fragment is attached to the activity. The advantage is to pull out this part of logic and realize no intrusion of activity. If you are familiar with Glide, the image loading library, you will know that it also uses transparent fragments to obtain the life cycle.
3.4 lifecycle event handling - lifecycle registry
Here, the processing of lifecycle events is transferred to lifecycle registry:
//LifecycleRegistry.java //The system defined map that saves the Observer can be added or deleted during traversal private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>(); public void handleLifecycleEvent(@NonNull Lifecycle.Event event) { State next = getStateAfter(event);//Gets the state to be in after the event occurs moveToState(next);//Move to this state } private void moveToState(State next) { if (mState == next) { return;//If it is consistent with the current status, it will not be processed } mState = next; //Assign new status if (mHandlingEvent || mAddingObserverCounter != 0) { mNewEventOccurred = true; return; } mHandlingEvent = true; sync(); //Synchronize lifecycle states to all observers mHandlingEvent = false; } 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()) { //isSynced() means that all observers are synchronized mNewEventOccurred = false; //Mbobservermap is the map used to store the observer after adding the observer in the activity 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; } ... static State getStateAfter(Event event) { switch (event) { case ON_CREATE: case ON_STOP: return CREATED; case ON_START: case ON_PAUSE: return STARTED; case ON_RESUME: return RESUMED; case ON_DESTROY: return DESTROYED; case ON_ANY: break; } throw new IllegalArgumentException("Unexpected event value " + event); }
The logic is clear: use getStateAfter() to get the state to be in after the event occurs (see the previous figure for a good understanding), moveToState() is to move to a new state, and finally use sync() to synchronize the lifecycle state to all observers.
Notice that there is a while loop in sync(), which is obviously traversing the observer. It is obvious that observers are stored in the mObserverMap, and the addition of observers in the mObserverMap is obviously the use of getLifecycle().addObserver() in the Activity. Here:
//LifecycleRegistry.java @Override public void addObserver(@NonNull LifecycleObserver observer) { State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED; //Observer with state: the function of this state: after a new event is triggered, when traversing and notifying all observers, judge whether the observer has been notified ObserverWithState statefulObserver = new ObserverWithState(observer, initialState); ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); //With observer as the key and observer withstate as the value, save it to the mobervermap if (previous != null) { return;//It has been added and will not be processed } LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); if (lifecycleOwner == null) { return;//lifecycleOwner exits without processing } //The logic of the following code: continuously synchronize the state of the new observer to the latest state mState through the while loop. //It means that although it may be added late, the previous events are distributed to you one by one (upEvent method), that is, stickiness boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent; State targetState = calculateTargetState(observer);//Calculate target status 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) { sync(); } mAddingObserverCounter--; }
Use observer to create an observer with state. Observer is used as the key and observer with state is used as the value, and saved in the mObserverMap. Then make a security judgment, and finally continuously synchronize the state of the new observer to the latest state mState, which means that although it may be added late, the previous events will be distributed to you one by one, that is, stickiness.
Go back to the while loop of sync() and see how to handle the distribution event:
private void sync() { LifecycleOwner lifecycleOwner = 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; // 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; } private boolean isSynced() { if (mObserverMap.size() == 0) { return true; }//The state of the oldest and the latest observers is consistent, and both are the current state of the owner, indicating that the synchronization has been completed State eldestObserverState = mObserverMap.eldest().getValue().mState; State newestObserverState = mObserverMap.newest().getValue().mState; return eldestObserverState == newestObserverState && mState == newestObserverState; } private void forwardPass(LifecycleOwner lifecycleOwner) { Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator = mObserverMap.iteratorWithAdditions(); while (ascendingIterator.hasNext() && !mNewEventOccurred) {//Forward traversal, from old to new 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));//Get events from observer popParentState(); } } } private void backwardPass(LifecycleOwner lifecycleOwner) { Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator = mObserverMap.descendingIterator(); while (descendingIterator.hasNext() && !mNewEventOccurred) {//Reverse traversal, from new to old 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);//Get events from observer popParentState(); } } }
The cycle condition is! isSynced(), if the state of the oldest and the latest observers is the same, and both are the current state of the owner, it indicates that the synchronization has been completed.
Enter the loop body before synchronization:
- mState is smaller than the oldest observer state. Backwardpass (lifecycle owner): distribute from new to old, and recycle downEvent() and observer.dispatchEvent() to continuously distribute events;
- mState is larger than the latest observer state. Go forward pass (lifecycle owner): distribute from old to new, and recycle upEvent() and observer.dispatchEvent() to continuously distribute events.
Then the observer of observer withstate type gets the event, namely observer. DispatchEvent (lifecycle owner, event). Let's see how it enables the annotated method to execute.
3.5 method execution after event callback
Let's continue to look at ObserverWithState:
static class ObserverWithState { State mState; GenericLifecycleObserver mLifecycleObserver; ObserverWithState(LifecycleObserver observer, State initialState) { mLifecycleObserver = Lifecycling.getCallback(observer); mState = initialState; } void dispatchEvent(LifecycleOwner owner, Event event) { State newState = getStateAfter(event); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; } }
mState is used to judge whether the observer has been notified when traversing all observers after a new event is triggered, that is, to prevent repeated notifications.
Mlicycleobserver is an instance of genericcycleobserver obtained using lifecycle. Getcallback (observer). GenericLifecycleObserver is an interface inherited from LifecycleObserver:
//Accept life cycle changes and distribute them to real observers public interface LifecycleEventObserver extends LifecycleObserver { //Life cycle state change void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event); }
In other words, LifecycleEventObserver increases the ability of LifecycleObserver to perceive life cycle state changes.
Look at lifecycle. Getcallback (observer):
@NonNull static LifecycleEventObserver lifecycleEventObserver(Object object) { ...Omit code for many types of judgment return new ReflectiveGenericLifecycleObserver(object); }
There are many codes to judge the type of observer in the method. We focus on ComponentActivity here, so the implementation class of LifecycleEventObserver is ReflectiveGenericLifecycleObserver:
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver { private final Object mWrapped; private final CallbackInfo mInfo; ReflectiveGenericLifecycleObserver(Object wrapped) { mWrapped = wrapped; mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());//It stores the information of event and annotated method } @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) { mInfo.invokeCallbacks(source, event, mWrapped);//Execute the method of the observer corresponding to the event } }
Its onStateChanged() method internally uses the invokeCallbacks method of CallbackInfo, which should be the method of executing the observer.
The classeinfo cache uses a Map to store the callback information of all observers. CallbackInfo is the callback information of the current observer.
Let's take a look at the creation of CallbackInfo instance, ClassesInfoCache.sInstance.getInfo(mWrapped.getClass()):
//ClassesInfoCache.java private final Map<Class, CallbackInfo> mCallbackMap = new HashMap<>();//Callback information for all observers private final Map<Class, Boolean> mHasLifecycleMethods = new HashMap<>();//Does the observer annotate the life cycle approach CallbackInfo getInfo(Class<?> klass) { CallbackInfo existing = mCallbackMap.get(klass);//If the current observer already exists, the callback information is retrieved directly if (existing != null) { return existing; } existing = createInfo(klass, null);//No, just collect information and create it return existing; } private CallbackInfo createInfo(Class<?> klass, @Nullable Method[] declaredMethods) { Class<?> superclass = klass.getSuperclass(); Map<MethodReference, Lifecycle.Event> handlerToEvent = new HashMap<>();//Methods corresponding to the arrival of life cycle events ... Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);//Reflection method for acquiring observer boolean hasLifecycleMethods = false; for (Method method : methods) {//Traverse the method to find the annotation onllifecycle event OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class); if (annotation == null) { continue; //return if onllifecycle event is not annotated } hasLifecycleMethods = true;//Annotated onllifecycle event Class<?>[] params = method.getParameterTypes(); //Get method parameters int callType = CALL_TYPE_NO_ARG; if (params.length > 0) { //With parameters callType = CALL_TYPE_PROVIDER; if (!params[0].isAssignableFrom(LifecycleOwner.class)) { throw new IllegalArgumentException(//The first parameter must be lifecycle owner "invalid parameter type. Must be one and instanceof LifecycleOwner"); } } Lifecycle.Event event = annotation.value(); if (params.length > 1) { callType = CALL_TYPE_PROVIDER_WITH_EVENT; if (!params[1].isAssignableFrom(Lifecycle.Event.class)) { throw new IllegalArgumentException(//The second parameter must be Event "invalid parameter type. second arg must be an event"); } if (event != Lifecycle.Event.ON_ANY) { throw new IllegalArgumentException(//There are two parameters. The annotation value can only be ON_ANY "Second arg is supported only for ON_ANY value"); } } if (params.length > 2) { //You cannot have more than two parameters throw new IllegalArgumentException("cannot have more than 2 params"); } MethodReference methodReference = new MethodReference(callType, method); verifyAndPutHandler(handlerToEvent, methodReference, event, klass);//Verify the method and add it to map handlerToEvent } CallbackInfo info = new CallbackInfo(handlerToEvent);//Get the method handlerToEvent of all annotation lifecycles and construct callback information instances mCallbackMap.put(klass, info);//Save the callback information of the current observer into the classeinfo cache mHasLifecycleMethods.put(klass, hasLifecycleMethods);//Record whether the observer has annotated the life cycle return info; }
- If the current observer callback information does not exist, the createInfo() method is used to collect the created callback information
- First reflect the method to obtain the observer, traverse the method, find the method annotated with onllifecycle event, and verify the parameters of the method.
- The first parameter must be lifecycle owner; The second parameter must be Event; There are two parameters. The annotation value can only be ON_ANY; You cannot have more than two parameters
- Verify the method and add it to the map. key is the method and value is the Event. map handlerToEvent is all methods that annotate the life cycle.
- After traversal, use handlerToEvent to construct the callback information CallbackInfo of the current observer, store it in the mCallbackMap of the ClassesInfoCache, and record whether the observer has annotated the life cycle method.
The overall idea is still very clear. Continue to look at the invokeCallbacks method of CallbackInfo:
static class CallbackInfo { final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers;//Multiple methods corresponding to Event final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;//Method to callback CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) { mHandlerToEvent = handlerToEvent; mEventToHandlers = new HashMap<>(); //Here, traverse the mHandlerToEvent to get mEventToHandlers for (Map.Entry<MethodReference, Lifecycle.Event> entry : handlerToEvent.entrySet()) { Lifecycle.Event event = entry.getValue(); List<MethodReference> methodReferences = mEventToHandlers.get(event); if (methodReferences == null) { methodReferences = new ArrayList<>(); mEventToHandlers.put(event, methodReferences); } methodReferences.add(entry.getKey()); } } @SuppressWarnings("ConstantConditions") void invokeCallbacks(LifecycleOwner source, Lifecycle.Event event, Object target) { invokeMethodsForEvent(mEventToHandlers.get(event), source, event, target);//Execute the method corresponding to the event invokeMethodsForEvent(mEventToHandlers.get(Lifecycle.Event.ON_ANY), source, event,target);//Execute annotation ON_ANY's method } 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--) {//Execute multiple methods corresponding to Event handlers.get(i).invokeCallback(source, event, mWrapped); } } } }
It is well understood that the method corresponding to the event is executed and the annotation is executed_ Any's method. mEventToHandlers is obtained by traversing the meventtoevent when creating the CallbackInfo, and stores multiple methods corresponding to each event.
Finally, take a look at handlers.get(i).invokeCallback, that is, in MethodReference:
static class MethodReference { ... void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) { try { switch (mCallType) { case CALL_TYPE_NO_ARG: mMethod.invoke(target);//Without parameters break; case CALL_TYPE_PROVIDER: mMethod.invoke(target, source);//One parameter: lifecycle owner break; case CALL_TYPE_PROVIDER_WITH_EVENT: mMethod.invoke(target, source, event);//Two parameters: lifecycle owner, Event break; } } ... } ... }
Execute corresponding methods according to different parameter types.
Here, the whole process is complete. After actually looking at such a large circle, the basic idea is consistent with our conjecture.
Borrow here The Android Jetpack architecture component (III) takes you to understand Lifecycle (principle) The figure below summarizes:
4, Summary
This article first introduces the concepts of Jetpack and AAC, which are the general development tool set officially recommended by Android. AAC is the architecture component, which is the introduction of this series of articles. Then it introduces the basic component Lifecycle of AAC, which enables developers to better manage the Activity/Fragment Lifecycle. Finally, the source code and principle of Lifecycle are analyzed in detail.
Jetpack's AAC is not only the necessary knowledge for our subsequent development of Android, but also the basis for completing the MVVM architecture. Lifecycle is the foundation of AAC, so it is necessary to master this article completely.
Thanks and reference:
Lifecycle official documentation
The Android Jetpack architecture component (III) takes you to understand Lifecycle (principle)
Android architecture component (2) lifecycle registry source code analysis