Jetpack AAC Series:

(1) Lifecycle will be fully mastered!

“Finally get it” series: Jetpack AAC complete analysis (2) Fully master LiveData!

“Finally get it” series: Jetpack AAC complete analysis (3) fully master the ViewModel!

“Finally Get it” series: Jetpack AAC Complete Analysis (iv) MVVM – Android Architecture Exploration!

“Finally Get it” series: Jetpack AAC Complete Analysis (5) DataBinding re-cognition!

Welcome to follow my public account, wechat search Hu Feiyang, article updates can be the first time to receive.

An introduction to Android Jetpack

1.1 the Jetpack is what

The official definition is:

Jetpack is a suite of libraries that help developers follow best practices, reduce boilerplate code and write code that runs consistently across Android versions and devices, allowing developers to focus on the code that matters.

JetPack is more of a concept and attitude. It is a collection of SDKS/specifications that are not part of the Android Framework SDK developed by Google, but are essential/recommended for Android development. Google has reorganized its Android ecosystem and set the direction for the future of Android development.

There are several benefits to using Jetpack:

  • Following best practices, Android Jetpack components are built with the latest design methods and are backward compatible to reduce crashes and memory leaks.
  • Eliminating boilerplate code, Android Jetpack manages a variety of tedious activities (such as background tasks, navigation, and lifecycle management) so you can focus on building great applications.
  • By reducing inconsistencies, these libraries can work in a consistent way across Android versions and devices, helping you reduce complexity.

Jetpack was originally a Jetpack, and it’s a pretty good idea to put it on Android and soar into the sky

That is, Jetpack is a set of tools to help developers develop applications efficiently. So what does this tool consist of?

1.2 Jetpack classification

The classification is shown in the following figure (this figure can not be found on the official website now) :

The Android Jetpack component covers four areas: Architecture, Foundation, Behavior, and UI.

The real gems are Architecture, which stands for Android Architecture Component (AAC).

It includes the more successful Lifecycle, LiveData, ViewModel and is also our best framework tool for using the MVVM pattern, which can be used in combination or alone.

The above is basically the introduction of the website, our main goal is to master the COMPONENTS of AAC, in-depth understanding and apply to the MVVM architecture.

In Jetpack, there will be a Lifecycle. There will be a Lifecycle.

Second, the Lifecycle

Lifecycle, as the name suggests, is the Lifecycle used to help developers manage activities and fragments. It is the basis for Both LiveData and ViewModel. Let’s start with why and how Lifecycle is used.

2.1 before the Lifecycle

The official documentation has an example of how Lifecycle was managed before Lifecycle was used:

Suppose we have an Activity that displays the location of the device on the screen. A common implementation might look like this:

    class MyLocationListener {
        public MyLocationListener(Context context, Callback callback) {
            // ...
        }

        void start(a) {
            // Connect to the system location service
        }

        void stop(a) {
            // Disconnect the system location service}}class MyActivity extends AppCompatActivity {
        private MyLocationListener myLocationListener;

        @Override
        public void onCreate(...). {
            myLocationListener = new MyLocationListener(this, (location) -> {
                / / update the UI
            });
        }

        @Override
        public void onStart(a) {
            super.onStart();
            myLocationListener.start();
            // Manage other components that need to respond to the Activity lifecycle
        }

        @Override
        public void onStop(a) {
            super.onStop();
            myLocationListener.stop();
            // Manage other components that need to respond to the Activity lifecycle}}Copy the code

While this example seems fine, in a real application, you end up with too many calls to the administrative interface and other components in response to the current state of the lifecycle. Managing multiple components places a large amount 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 if we need to run an operation for a long time, such as some kind of configuration check in onStart(). In this case, the onStop() method of myLocationListener is called before onStart(), which causes the component to persist longer than needed, resulting in internal leaks. As follows:

    class MyActivity extends AppCompatActivity {
        private MyLocationListener myLocationListener;

        public void onCreate(...). {
            myLocationListener = new MyLocationListener(this, location -> {
                / / update the UI
            });
        }

        @Override
        public void onStart(a) {
            super.onStart();
            Util.checkUserStatus(result -> {
                // If checkUserStatus takes a long time to call back after the activity has stopped, then myLocationListener will not be able to stop() after it has started.
                // Because myLocationListener holds the activity, there is a memory leak.
                if(result) { myLocationListener.start(); }}); }@Override
        public void onStop(a) {
            super.onStop(); myLocationListener.stop(); }}Copy the code

Namely, two problem points:

  • The activity lifecycle contains a large amount of code that manages components and is difficult to maintain.
  • There is no guarantee that the component will not start after the Activity/Fragment is stopped

Lifecycle libraries address these issues in a flexible and isolated manner.

2.2 Use of Lifecycle

Lifecycle is a library and also contains a class called Lifecycle, which stores information about the Lifecycle state of a component, such as an Activity or Fragment, and allows other objects to observe this state.

2.2.1 Importing a Dependency

1. Non-androidx project introduction:

implementation "Android. Arch. Lifecycle: extensions: 1.1.1"
Copy the code

Adding this code relies on the following library:

2. Introduction of androidX project:

If the project already relies on AndroidX:

implementation 'androidx. Appcompat: appcompat: 1.2.0'
Copy the code

Then we can use the Lifecycle library because appcompat depends on androidx.fragment which depends on ViewModel and LiveData which depends on Lifecycle internally.

If you want to introduce dependencies separately, do the following:

Add the Google () code base to build.gradle in the project root directory, and then the app’s build.gradle introduces the dependencies.

// Build. Gradle for the root directory
    repositories {
        google()
        ...
    }

/ / app build. Gradle
    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 handler
        annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // replace - if Java8 is used, replace the above lifecycle compiler with this
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

	// The following is imported as needed
        // Optional - Help implement the Service LifecycleOwner
        implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
        // Optional - ProcessLifecycleOwner 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"
    }
    
Copy the code

It looks like a lot. In fact, if Lifecycle was all that was needed, Lifecycle runtime would be all that was needed. But they are usually used in conjunction with ViewModel and LiveData, so lifecycle- ViewModel and lifecycle- LiveData are usually introduced as well.

In addition, lifecycle-process is the provision of a lifecycle for the entire app process, which will be mentioned in the meeting.

2.2.2 Usage

The use of Lifecycle is simple:

  • (1) Lifecycle owners use getLifecycle() to retrieve Lifecycle instances and add observers instead of addObserve();
  • 2, the observer implementation LifecycleObserver, using OnLifecycleEvent annotation on the method to pay attention to the corresponding lifecycle, lifecycle triggered will execute the corresponding method;

2.2.2.1 Basic usage

Common usage in an Activity (or Fragment) 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 Indicates the Lifecycle
        getLifecycle().addObserver(new MyObserver());
        Log.i(TAG, "onCreate: ");
    }
    @Override
    protected void onResume(a) {
        super.onResume();
        Log.i(TAG, "onResume: ");
    }
    @Override
    protected void onPause(a) {
        super.onPause();
        Log.i(TAG, "onPause: "); }}Copy the code

The Activity (or Fragment) is the owner of the Lifecycle. The Lifecycle object is obtained by the getLifecycle() method. The Lifecycle object uses the addObserver method to add observers to itself, the MyObserver object. MyObserver can sense when there is a change in Lifecycle’s Lifecycle.

How does MyObserver use the lifecycle? Take a look at the MyObserver implementation:

public class MyObserver implements LifecycleObserver {

    private String TAG = "Lifecycle_Test";
    
    @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME)
    public void connect(a){
        Log.i(TAG, "connect: ");
    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE)
    public void disConnect(a){
        Log.i(TAG, "disConnect: "); }}Copy the code

First, MyObserver implements the LifecycleObserver interface, which is used to mark a class as a LifecycleObserver. Then add the @onlifecyCleEvent annotation to connectListener() and disconnectListener(), respectively. If (value = Lifecycle.Event.ON_RESUME) and (value = Lifecycle. ConnectListener () is executed on ON_RESUME, and disconnectListener() is executed on ON_PAUSE.

We open LifecycleTestActivity and exit, and the log prints as follows:

2020-11- 0917:25:40.601 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onCreate: 

2020-11- 0917:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onResume: 
2020-11- 0917:25:40.605 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: connect: 

2020-11- 0917:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: disConnect: 
2020-11- 0917:25:51.841 4822-4822/com.hfy.androidlearning I/Lifecycle_Test: onPause: 
Copy the code

Visible MyObserver methods are indeed invoked when the corresponding lifecycle of concern is triggered. Of course you can also write the value in the annotation as any other Lifecycle you care about, such as Lifecycle.event.on_destroy.

2.2.2.2 Use in the MVP architecture

In MVP architecture, 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 Indicates the Lifecycle
// getLifecycle().addObserver(new MyObserver());

        // Lifecycle is used in MVP
        getLifecycle().addObserver(new MyPresenter(this));
        Log.i(TAG, "onCreate: ");
    }

    @Override
    protected void onResume(a) {
        super.onResume();
        Log.i(TAG, "onResume: ");
    }
    @Override
    protected void onPause(a) {
        super.onPause();
        Log.i(TAG, "onPause: ");
    }

    @Override
    public void showView(a) {}
    @Override
    public void hideView(a) {}}//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 to check the current lifecycle status after the callback
                if(owner.getLifecycle().getCurrentState().isAtLeast(STARTED)) { start(); mView.showView(); }}); }@OnLifecycleEvent(value = Lifecycle.Event.ON_STOP)
    private void hideDataOnStop(a){
        Log.i(TAG, "hideDataOnStop: "); stop(); mView.hideView(); }}//IView
interface IView {
    void showView(a);
    void hideView(a);
}
Copy the code

This is where the Presenter implements the LifecycleObserver interface, also annotating the Lifecycle to be triggered on the method, and finally adding it to Lifecycle as an observer in the Activity.

What are the benefits? MyPresenter can recognize and execute methods when the Activity lifecycle changes, without calling MyPresenter’s methods among MainActivity’s multiple lifecycle methods.

  • All method invocation operations are managed by the component itself: the Presenter class is automatically aware of the lifecycle, and if you want to use the Presenter in other activities or fragments, just add it as an observer.
  • Let each component store its own logic, reduce the code in the Activity/Fragment, easier to manage;

The first problem point mentioned above is solved.

In addition, notice that getDataOnStart() checks the current lifecycle status after the time verification callback: the start() method is not continued until the Activity is at least in the STARTED state, which ensures that the start() method is not performed when the Activity is stopped;

The second problem point mentioned above has also been solved.

2.2.3 Customizing LifecycleOwner

Calling getLifecycle() in an Activity can fetch an instance of Lifecycle. Where is getLifecycle() defined? Is the interface LifecycleOwner, LifecycleOwner:

/** * Lifecycle owner * Lifecycle events can be used by custom components to handle lifecycle event changes without writing any code in the Activity/Fragmen */
public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle(a);
}
Copy the code

Support Library 26.1.0 and above, AndroidX fragments and activities already implement the LifecycleOwner interface, so we can use getLifecycle() directly in an Activity.

If you have a custom class and want to make it a LifecycleOwner, you can use the LifecycleRegistry class, which is Lifecycle’s implementation class but needs to forward events to that 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(a) {
            super.onStart();
            lifecycleRegistry.markState(Lifecycle.State.STARTED);
        }
        @NonNull
        @Override
        public Lifecycle getLifecycle(a) {
            returnlifecycleRegistry; }}Copy the code

MyActivity implements LifecycleOwner, and getLifecycle() returns the lifecycleRegistry instance. The lifecycleRegistry instance is created on onCreate and the markState() method is called to complete the passing of lifecycle events for each lifecycle. This completes the customization of the LifecycleOwner, which means that MyActivity becomes a LifecycleOwner and can then be used with components that implement the LifecycleObserver.

In addition, the observer method can accept a parameter LifecycleOwner, which can be used either to get the current state or to continue adding observers. If ON_ANY is annotated, you 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()}}Copy the code

2.3 Application Lifecycle ProcessLifecycleOwner

Before the App to enter Taiwan before and after judgment is through registerActivityLifecycleCallbacks (the callback) method, and then use a global variable in the callback do count, in onActivityStarted count + 1 (), The count is subtracted by 1 in the onActivityStopped method to determine the foreground/background switch.

ProcessLifecycleOwner can be used to directly obtain the application front and back switchover status. (Remember to introduce the lifecycle dependencies first)

Use method and the Activity of similar, only to use ProcessLifecycleOwner. The get () to obtain ProcessLifecycleOwner, code is as follows:

public class MyApplication extends Application {

    @Override
    public void onCreate(a) {
        super.onCreate();

	// Register App Lifecycle Observer
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationLifecycleObserver());
    }
    
    /** * Lifecycle.event.on_create will be distributed only once and lifecycle.event.on_Destroy will not be distributed. * * When the first Activity enters, ProcessLifecycleOwner will dispatch Lifecycle.Event.ON_START, Lifecycle. * While Lifecycle.event.ON_PAUSE, Lifecycle.event.ON_STOP, will be delayed distribution after the last Activit exits. This delay is sufficient to ensure that ProcessLifecycleOwner does not send any events if the activity is destroyed and recreated due to configuration changes. * * Function: listen for applications to enter the foreground or background */
    private static class ApplicationLifecycleObserver implements LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        private void onAppForeground(a) {
            Log.w(TAG, "ApplicationObserver: app moved to foreground");
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        private void onAppBackground(a) {
            Log.w(TAG, "ApplicationObserver: app moved to background"); }}}Copy the code

It’s really simple to see that Lifecycle usage is almost the same as the previous Activity and that our use of ProcessLifecycleOwner is elegant. The lifecycle distribution logic is explained in the comments.

Three, source code analysis

Lifecycle is simple to use and Lifecycle principles and source code are resolved.

Here’s a guess: The LifecycleOwner (such as an Activity) iterates through the observers when the lifecycle state changes (that is, when the lifecycle method executes), getting the annotation on each observer’s method. If the annotation is @onlifecycleEvent and the value is consistent with the lifecycle state, So just execute this method. Is that a reasonable guess? Here you take a look.

3.1 Lifecycle class

Look at Lifecycle:

public abstract class Lifecycle {
    // Add an observer
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);
    // Remove the observer
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);
    // Get the current state
    public abstract State getCurrentState(a);

// Lifecycle event, corresponding to the 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
    }
    
    // Life cycle state (Event is the Event that enters this state)
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;

        // Determine at least one state
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0; }}Copy the code

Lifecycle uses two main enumerations to track the Lifecycle state of its associated components:

  1. These events correspond to the Activity/Fragment lifecycle methods.
  2. State, life cycle State, and Event refers to the Event that enters a State.

Timing of Event trigger:

  • The ON_CREATE, ON_START, and ON_RESUME events are distributed after the execution of the LifecycleOwner method.
  • The ON_PAUSE, ON_STOP, and ON_DESTROY events are distributed before the call to the LifecycleOwner method.

This ensures that LifecycleOwner is in this state.

The official website has a very clear picture:

3.2 Activity Implementation of LifecycleOwner

Activity to achieve the above mentioned LifecycleOwner, so can directly use getLifecycle (), is in the androidx.activity.Com ponentActivity:

/ / androidx.activity.Com ponentActivity, ignores some other code here, we only see the Lifecycle
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); // Use ReportFragment to distribute lifecycle events
        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(a) {
        returnmLifecycleRegistry; }}Copy the code

Some other code is ignored here and we will only look at Lifecycle.

See that ComponentActivity implements the interface LifecycleOwner and returns the LifecycleRegistry instance at getLifecycle(). LifecycleRegistry was mentioned earlier as a Lifecycle concrete implementation.

Then set the State of mLifecycleRegistry to state.created in onSaveInstanceState(). Why is it not handled in other lifecycle methods? What? That’s not what I thought. Don’t worry, in the onCreate () : there was a line of ReportFragment. InjectIfNeededIn (this); That’s the point.

3.3 Life Cycle Event Distribution — ReportFragment

// Fragment for 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 register callbacks directly to get the lifecycle
            activity.registerActivityLifecycleCallbacks(
                    new LifecycleCallbacks());
        }
        // Before API29, use fragments to obtain the life cycle
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(newReportFragment(), 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. 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 LifecycleRegistry's handleLifecycleEvent method to handle events}}}@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatch(Lifecycle.Event.ON_CREATE);
    }
    @Override
    public void onStart(a) {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }
    @Override
    public void onResume(a) {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }
    @Override
    public void onPause(a) {
        super.onPause(); dispatch(Lifecycle.Event.ON_PAUSE); }... Omit 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); }... OnStop, onDestroy}}Copy the code

InjectIfNeededIn () first makes a version distinction: 29 and above the API directly using the activity of registerActivityLifecycleCallbacks directly registered the lifecycle callbacks, then to the current activity added ReportFragment, Notice that this fragment has no layout.

Then, LifecycleCallbacks and fragments all end up in the Dispatch (Activity Activity, Lifecycle.Event Event) method, Internally, LifecycleRegistry’s handleLifecycleEvent method is used to handle events.

The ReportFragment is only used to retrieve the lifecycle, because the fragment lifecycle is dependent on the Activity. The benefit is that this part of the logic is removed to make the activity non-intrusive. If you’re familiar with image loading library Glide, you know that it also uses transparent fragments to get the lifecycle.

3.4 Lifecycle event processing — LifecycleRegistry

At this point, the processing of lifecycle events has been moved to LifecycleRegistry:

//LifecycleRegistry.java
   // The map of the Observer can be added or deleted during the traversal
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();
            
    public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);// Get the state that the event will be in after it occurs
        moveToState(next);// Move to this state
    }

    private void moveToState(State next) {
        if (mState == next) {
            return;// If it is the same as the current state, no processing is required
        }
        mState = next; // Assign the new state
        if(mHandlingEvent || mAddingObserverCounter ! =0) {
            mNewEventOccurred = true;
            return;
        }
        mHandlingEvent = true;
        sync(); // Synchronize the lifecycle state to all observers
        mHandlingEvent = false;
    }
    
        private void sync(a) {
        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;
            //mObserverMap is the map used to hold the observer after the activity is added
            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);
    }
Copy the code

The logic is clear: use getStateAfter() to get the state that the event will be in after the event has occurred (see the previous diagram to make sense), moveToState() to move to the new state, and finally sync() to synchronize the lifecycle state to all observers.

Notice that sync() has a while loop, which is clearly traversing the observer. And obviously the observer is in the mObserverMap and mObserverMap adds the observer to the Activity by using getLifecycle().addobServer () here:

//LifecycleRegistry.java
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        // An observer with a state. This state is used to determine whether this observer has been notified when a new event is fired and traverses all observers
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
        // Use the ObserverWithState as the value to store the mObserverMap

        if(previous ! =null) {
            return;// It has already 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: the new observer's state is continuously synchronized to the latest state mState via a while loop.
    // This means that the previous events are distributed to you one by one, even though they may be added late (upEvent method)
        booleanisReentrance = mAddingObserverCounter ! =0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);// Calculate the target state
        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--; }Copy the code

Use an observer to create an ObserverWithState. The ObserverWithState is the key and the ObserverWithState is the value. The ObserverWithState is stored in the mObserverMap. Then the security judgment is made, and finally the state of the new observer is continuously synchronized to the latest state mState, meaning: although it may be added late, but the previous events will be distributed to you one by one, namely stickiness.

Go back to the while loop just sync() and see how the distribution event is handled:

    private void sync(a) {
        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(a) {
        if (mObserverMap.size() == 0) {
            return true; 
        }// The state of the oldest observer is the same as that of the newest observer, which is the current state of ower, indicating that synchronization has finished
        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) {// Iterate forward, 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));// Observer Gets eventspopParentState(); }}}private void backwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator = mObserverMap.descendingIterator();
        while(descendingIterator.hasNext() && ! mNewEventOccurred) {// Iterate backwards, 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);// Observer Gets eventspopParentState(); }}}Copy the code

The loop condition is! IsSynced (), if the state of the oldest and newest observer is the same, and both are the current state of Ower, then synchronization is over.

Enter the loop body without completing synchronization:

  • If the mState is smaller than the oldest observer state, go backwardPass(lifecycleOwner) : from new to old distribution, loop downEvent() and observer.dispatchEvent() to distribute events continuously;
  • MState is larger than the latest observer state, go forwardPass(lifecycleOwner) : Distribute from old to new, using upEvent() and observer.dispatchEvent(), and distribute events continuously.

The ObserverWithState type observer then gets the event, observer.dispatchEvent(lifecycleOwner, Event), and let’s see how it makes the annotated method execute.

3.5 Method execution after event callback

Let’s move on to 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; }}Copy the code

The function of mState is to determine whether the observer has been notified when a new event is triggered by traversing all observers, which prevents duplicate notifications.

MLifecycleObserver is a GenericLifecycleObserver instance obtained using Lifecycling. GetCallback (observer). GenericLifecycleObserver is the interface, inherited from LifecycleObserver:

// Accept life cycle changes and distribute them to real observers
public interface LifecycleEventObserver extends LifecycleObserver {
    // Life cycle status changes
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
Copy the code

That said, LifecycleEventObserver adds the ability to LifecycleObserver to sense life cycle state changes.

See Lifecycling. GetCallback (observer) :

    @NonNull
    static LifecycleEventObserver lifecycleEventObserver(Object object) {... Omit a lot of type determination codereturn new ReflectiveGenericLifecycleObserver(object);
    }
Copy the code

Methods there were a lot of code to determine the types of the observer, we focus on here is ComponentActivity, so the implementation class is ReflectiveGenericLifecycleObserver LifecycleEventObserver:

class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
    private final Object mWrapped;
    private final CallbackInfo mInfo;

    ReflectiveGenericLifecycleObserver(Object wrapped) {
        mWrapped = wrapped;
        mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());// Stores the event and annotated method information
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Event event) {
        mInfo.invokeCallbacks(source, event, mWrapped);// Execute the observer method corresponding to the event}}Copy the code

Its onStateChanged() method internally uses the invokeCallbacks method of CallbackInfo, which should be the execution observer method here.

ClassesInfoCache internally uses a Map to store the callback information for all observers. CallbackInfo is the callback information for the current observer.

To look at the first CallbackInfo instances created, 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 have a method that annotates the lifecycle
    
    CallbackInfo getInfo(Class
        klass) {
        CallbackInfo existing = mCallbackMap.get(klass);// If the current observer already exists, the callback information is fetched directly
        if(existing ! =null) {
            return existing;
        }
        existing = createInfo(klass, null);// Do not collect information and create
        return existing;
    }
    
    private CallbackInfo createInfo(Class<? > klass,@Nullable Method[] declaredMethods) { Class<? > superclass = klass.getSuperclass(); Map<MethodReference, Lifecycle.Event> handlerToEvent =new HashMap<>();// Life cycle event arrival corresponding method. Method[] methods = declaredMethods ! =null ? declaredMethods : getDeclaredMethods(klass);// Reflect the method of getting the observer
        boolean hasLifecycleMethods = false;
        for (Method method : methods) {// Iterate through the method to find the annotation OnLifecycleEvent
            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
            if (annotation == null) {
                continue; // Return OnLifecycleEvent without annotation
            }
            hasLifecycleMethods = true;// There is an annotation OnLifecycleEventClass<? >[] params = method.getParameterTypes();// Get the method parameters
            int callType = CALL_TYPE_NO_ARG;
            if (params.length > 0) { / / a parameter
                callType = CALL_TYPE_PROVIDER;
                if(! params[0].isAssignableFrom(LifecycleOwner.class)) {
                    throw new IllegalArgumentException(// The first argument must be LifecycleOwner
                            "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 argument must be Event
                            "invalid parameter type. second arg must be an event");
                }
                if(event ! = Lifecycle.Event.ON_ANY) {throw new IllegalArgumentException(// There are two arguments that indicate that the value can only be ON_ANY
                            "Second arg is supported only for ON_ANY value"); }}if (params.length > 2) { // No more than two parameters
                throw new IllegalArgumentException("cannot have more than 2 params");
            }
            MethodReference methodReference = new MethodReference(callType, method);
            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);// Validates the method and adds it to the Map handlerToEvent
        }
        CallbackInfo info = new CallbackInfo(handlerToEvent);// Get all the annotation lifecycle method handlerToEvent, and construct the callback information instance
        mCallbackMap.put(klass, info);// Save the current observer callback information in ClassesInfoCache
        mHasLifecycleMethods.put(klass, hasLifecycleMethods);// Note whether the observer has a method that notes the lifecycle
        return info;
    }
Copy the code
  • If no current observer callback information exists, the createInfo() method is used to collect the creation
  • First reflect the method that gets the observer, walk through the method to find the method that annotates OnLifecycleEvent, and first check the parameters of the method.
  • The first argument must be LifecycleOwner; The second argument must be Event; There are two parameter annotations that the value can only be ON_ANY; There can be no more than two parameters
  • Validates the method and adds it to the map. Key is the method and value is the Event. Map handlerToEvent is all the methods that annotate the lifecycle.
  • After traversing, we use handlerToEvent to construct the CallbackInfo of the current observer, save it in the mCallbackMap of ClassesInfoCache, and record whether the observer has annotated the method of life cycle.

CallbackInfo invokeCallbacks = invokeCallbacks = invokeCallbacks = invokeCallbacks

    static class CallbackInfo {
        final Map<Lifecycle.Event, List<MethodReference>> mEventToHandlers;// Multiple methods corresponding to the Event
        final Map<MethodReference, Lifecycle.Event> mHandlerToEvent;// The method to call back

        CallbackInfo(Map<MethodReference, Lifecycle.Event> handlerToEvent) {
            mHandlerToEvent = handlerToEvent;
            mEventToHandlers = new HashMap<>();
            // Here we iterate through mHandlerToEvent to get the 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 = newArrayList<>(); 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 the method annotated ON_ANY
        }

        private static void invokeMethodsForEvent(List
       
         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 the Eventhandlers.get(i).invokeCallback(source, event, mWrapped); }}}}Copy the code

It makes sense to execute methods that correspond to event and execute methods that annotate ON_ANY. The mEventToHandlers are fetched by traversating the mHandlerToEvent when the CallbackInfo is created, and the methods for each Event are stored.

Handlers. Get (I). InvokeCallback (MethodReference) :

    static class MethodReference {...void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
            try {
                switch (mCallType) {
                    case CALL_TYPE_NO_ARG:
                        mMethod.invoke(target);// No parameters
                        break;
                    case CALL_TYPE_PROVIDER:
                        mMethod.invoke(target, source);// One parameter: LifecycleOwner
                        break;
                    case CALL_TYPE_PROVIDER_WITH_EVENT:
                        mMethod.invoke(target, source, event);// Two parameters: LifecycleOwner, Event
                        break; }}... }... }Copy the code

Perform different methods based on different parameter types.

At this point, the process is complete. In fact, the basic idea is the same as our guess.

Here is a summary of how Lifecycle can be understood in Android Jetpack Architecture Components (iii) :

Four,

This article begins with an introduction to the concepts of Jetpack and AAC, which is Android’s official recommended set of general purpose development tools. AAC is the architecture component and is the introduction to this series of articles. Lifecycle is the basic component of AAC, which allows developers to manage the Activity/Fragment Lifecycle. Finally Lifecycle source code and principle are analyzed in detail.

Jetpack’s AAC was essential for the rest of our Android development and was the basis for completing the MVVM architecture. Lifecycle is more fundamental to AAC, so it is necessary to fully understand this article.

.

Thanks and reference:

Lifecycle Official Documentation

Android Jetpack Architecture Components (Part 3) Will help you understand Lifecycle.

Android Architecture Components (2) LifecycleRegistry source analysis

.

Your likes and comments are a great encouragement to me!

Welcome to follow my public account: Hu Feiyang