An overview of the

At the Google IO conference in the past, Google introduced Android Architecture Components, and the Handling Lifecycles for Android Components were introduced.

At the same time, how to use the android.arch. Lifecycle class provided by the android.arch. Lifecycle package to control data, listeners and other lifecycle? At the same time, lifecycle of LiveData and ViewModel also depends on the lifecycle framework.

Lifecycle introduction & Basic use

Why should Lifecycle be introduced?

When dealing with the lifecycle of an Activity or Fragment component, we inevitably run into problems like this:

We initialize some members (such as a Presenter in the MVP architecture, or an AudioManager, or MediaPlayer, etc.) in the Activity’s onCreate(), then process them in onStop, and release them in onDestroy. As a result, our code might look like this:

class MyPresenter{
    public MyPresenter(a) {}void create(a) {
        //do something
    }

    void destroy(a) {
        //do something}}class MyActivity extends AppCompatActivity {
    private MyPresenter presenter;

    public void onCreate(...). {
        presenter= new MyPresenter ();
        presenter.create();
    }

    public void onDestroy(a) {
        super.onDestroy(); presenter.destory(); }}Copy the code

The code is fine, but the point is that in a production environment, such code would be very complex, and you would end up with too many similar calls and the onCreate() and onDestroy() methods would become bloated.

The solution

Lifecycle is a class that holds information about the Lifecycle state of a component, such as an Activity or Fragment, and allows other objects to observe this state.

We only need 2 steps:

1. Prestener inherits the LifecycleObserver interface

public interface IPresenter extends LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event);
}

public class BasePresenter implements IPresenter {
        
    private static final String TAG = "com.qingmei2.module.base.BasePresenter";    

    @Override
    public void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event) {}@Override
    public void onCreate(@NotNull LifecycleOwner owner) {
        Log.d("tag"."BasePresenter.onCreate" + this.getClass().toString());
    }

    @Override
    public void onDestroy(@NotNull LifecycleOwner owner) {
        Log.d("tag"."BasePresenter.onDestroy" + this.getClass().toString()); }}Copy the code

Here I directly list the events that I want to observe in the lifecycle of the Presenter and encapsulate them into the BasePresenter, so that each subclass of the BasePresenter can be aware of the lifecycle events of the Activity container and override the corresponding behavior in the methods of the subclass.

Add Observer to Activity/Fragment container

public class MainActivity extends AppCompatActivity {
    private IPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("tag"."onCreate" + this.getClass().toString());
        setContentView(R.layout.activity_main); mPresenter = new MainPresenter(this); getLifecycle().addObserver(mPresenter); // Add LifecycleObserver} @override protected voidonDestroy() {
        Log.d("tag"."onDestroy"+ this.getClass().toString()); super.onDestroy(); }}Copy the code

In this way, whenever the Activity has a corresponding lifecycle change, the Presenter will execute the corresponding event annotation method:

Lifecycle provides all of the Lifecycle events except onCreate and onDestroy events, which can be observed by LifecycleObserver by declaring them in annotations:

// The following is the logcat log 01-08 23:21:01.702 D/tag: OnCreate class com. Qingmei2. Mvparchitecture. MVP. UI. MainActivity 01-08 23:21:01. 778 D/tag: OnCreate class com. Qingmei2. Mvparchitecture. MVP. Presenter. MainPresenter 01-08 23:21:21. 074 D/tag: OnDestroy class com. Qingmei2. Mvparchitecture. MVP. Presenter. MainPresenter 01-08 23:21:21. 074 D/tag: onDestroy class com.qingmei2.mvparchitecture.mvp.ui.MainActivityCopy the code
 public enum Event {
        /**
         * Constant for onCreate event of the {@link LifecycleOwner}.
         */
        ON_CREATE,
        /**
         * Constant for onStart event of the {@link LifecycleOwner}.
         */
        ON_START,
        /**
         * Constant for onResume event of the {@link LifecycleOwner}.
         */
        ON_RESUME,
        /**
         * Constant for onPause event of the {@link LifecycleOwner}.
         */
        ON_PAUSE,
        /**
         * Constant for onStop event of the {@link LifecycleOwner}.
         */
        ON_STOP,
        /**
         * Constant for onDestroy event of the {@link LifecycleOwner}.
         */
        ON_DESTROY,
        /**
         * An {@link Event Event} constant that can be used to match all events.
         */
        ON_ANY
    }
Copy the code

Two, the principle analysis

First the conclusion:

A simple summary of the Android Architecture component (I) — Lifecycle, @Shymanzhu’s diagram:

Let’s first pick out the important classes:

  • LifecycleObserver interface (LifecycleObserver) : Classes that implement this interface can be annotated by the LifecycleOwner class’s addObserver(LifecycleObserver O) method. After being registered, The LifecycleObserver can then observe the LifecycleOwner’s lifecycle events.

  • LifecycleOwner interface (Lifecycle holder) : The class that implements this interface holds a Lifecycle object, and changes to the interface’s Lifecycle object are observed by its registered observer LifecycleObserver and trigger its corresponding event.

  • Lifecycle: Unlike the LifecycleOwner, which itself holds Lifecycle objects, LifecycleOwner obtains internal Lifecycle objects through its Lifecycle getLifecycle() interface.

  • State(State of the current lifecycle) : as shown in the figure.

  • Event(Event corresponding to current Lifecycle change) : As shown in the figure, when Lifecycle changes occur, such as onCreate, an ON_CREATE Event will be automatically emitted.

We’ll take Fragment as an example and look at the connection between the actual Fragment class and the above class or interface:

1. Fragment: LifecycleOwner

  • Fragment(Activity is the same, we take Fragment as an example, the same below) : The LifecycleOwner interface is implemented, which means that the Fragment object holds the Lifecycle object and can obtain the internal Lifecycle object through the Lifecycle getLifecycle() method:
public class Fragment implements xxx.LifecycleOwner {
    
    / /... Omit the other

   LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public Lifecycle getLifecycle(a) {
        returnmLifecycleRegistry; }}public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle(a);
}
Copy the code

As you can see, the getLifecycle() method implemented actually returns a LifecycleRegistry object, which actually inherits Lifecycle, more on that later.

What does having Lifecycle do? In fact, lifecycle events are sent to the internal LifecycleRegistry object during the Fragment’s lifecycle:

public class Fragment implements xxx, LifecycleOwner { //... void performCreate(Bundle savedInstanceState) { onCreate(savedInstanceState); //1. Execute the lifecycle method first //... Omit code / / 2. Life cycle events distribution mLifecycleRegistry. HandleLifecycleEvent (Lifecycle. Event. ON_CREATE); } voidperformStart() { onStart(); / /... mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); } voidperformResume() { onResume(); / /... mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); } voidperformPause() {/ / 3. Note that the call order changed mLifecycleRegistry. HandleLifecycleEvent (Lifecycle. Event. ON_PAUSE); / /... onPause(); } voidperformStop() { mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP); / /... onStop(); } voidperformDestroy() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        //...
        onDestroy();
    }
}
Copy the code

Different fragments go through different lifecycles, except for the lifecycle method onCreate/onStart/…. that is exposed to us At the same time, the Lifecycle object inside the Fragment (that is, mLifecycleRegistry) also passes the Lifecycle event as an argument to the handler () method.

Also, you’ll notice that the Fragment performCreate(), performStart(), and performResume() call their own onXXX() method first, Then call the handleLifecycleEvent() method of LifecycleRegistry; In performPause(), performStop(), and performDestroy(), LifecycleRegistry’s handleLifecycleEvent() method is called first and then onXXX() itself.

Refer to the sequence diagram in the Android Architecture Component (I) — Lifecycle, @Shymanzhu:

As you can see from the figure, LifecycleObserver can receive Lifecycle events when the Fragment gives them to its internal Lifecycle to process. How is this implemented?

LifecycleRegistry: Lifecycle

First of all, LifecycleRegistry is a subclass of Lifecycle:

public class LifecycleRegistry extends Lifecycle {
}
Copy the code

Let’s look at the Lifecycle class

Public abstract class Lifecycle {// Register LifecycleObserver (e.g., Presenter) public abstract void addObserver(@nonnull) LifecycleObserver observer); // Remove LifecycleObserver public abstract void removeObserver(@nonnull LifecycleObserver observer); Public abstract State getCurrentState(); public enum Event { ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY } public enum State { DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; public boolean isAtLeast(@NonNull State state) {returncompareTo(state) >= 0; }}}Copy the code

Lifecycle is nothing to talk about. Several abstract methods can be understood as well. As a subclass of Lifecycle, LifecycleRegistry can also register LifecycleObserver via the addObserver method. LifecycleRegistry notifies each registered LifecycleObserver one by one when the LifecycleRegistry’s own lifecycle changes (imagine that there must be a member variable State inside to record the current lifecycle). And executes the corresponding lifecycle method.

Let’s look at the handleLifecycleEvent() method of LifecycleRegistry:

    public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);
        moveToState(next);
    }
Copy the code

Lifecycle will change its State value by using getStateAfter to retrieve the current State that Lifecycle should be in. The LifecycleObserver is then traversed and synchronized and notified of changes in its state, thus triggering the lifecycle events corresponding to the LifecycleObserver.

In fact LifecycleRegistry itself still has a lot to mention, this article only explains the principle clearly, not involved in the source code in detail.

A few Tips

1. Try reuse LifecycleRegistry

First, LifecycleRegistry itself is a mature Lifecycle implementation class that is instantiated for use in activities and fragments. If we need to customize the LifecycleOwner and implement the interface we need to return an instance of Lifecycle. You can simply new a LifecycleRegistry member in your custom LifecycleOwner and return it (in short: just use it).

Here’s the official Google docs:

LifecycleRegistry: An implementation of Lifecycle that can handle multiple observers. It is used by Fragments and Support Library Activities. You can also directly use it if you have a custom LifecycleOwner.

2. Trade-offs between annotations and DefaultLifecycleObserver

Second, Google Lifecycle library provides a DefaultLifecycleObserver class, which is convenient for us to implement the LifecycleObserver interface directly. Compared to the annotating method used in the demo, Google officials recommend that we use the DefaultLifecycleObserver class and declare

Once Java 8 becomes mainstream on Android, annotations will be deprecated, so falling between DefaultLifecycleObserver and annotations, DefaultLifecycleObserver is preferred.

Official text:

/*
 * If you use <b>Java 8 Language</b>, then observe events with {@link DefaultLifecycleObserver}.
 * To include it you should add {@code "android.arch.lifecycle:common-java8:<version>"} to your * build.gradle file. * <pre> * class TestObserver implements DefaultLifecycleObserver { * {@literal @}Override  * public void onCreate(LifecycleOwner owner) { * // your code * } * } * </pre> * If you use <b>Java 7 Language</b>, Lifecycle events are observed using annotations. * Once Java 8 Language becomes mainstream on Android, annotations will be deprecated, so between * {@link DefaultLifecycleObserver} and annotations, * you must always prefer {@code DefaultLifecycleObserver}. */Copy the code

* 3, Lifecycles best practices

This section is excerpted from “Handling Lifecycles for Architecture Components” by Zly394, juejin.cn/post/684490…

  • Keep UI controllers (activities and fragments) as thin as possible. They shouldn’t try to get the data they need; Instead, use the ViewModel, and watch LiveData reflect data changes into the view.

  • Try to write a data-driven UI, where the responsibility of the UI controller is to update the view when data changes or to notify the ViewModel of the user’s actions.

  • Put the data logic in the ViewModel class. The ViewModel should serve as a connection between the UI controller and the rest of the application. Note: It is not the ViewModel’s responsibility to get the data (e.g., from the network). Instead, the ViewModel calls the corresponding component to fetch the data, and then feeds the result of the data fetch to the UI controller.

  • Use Data Binding to keep the interface between the view and the UI controller clean. This makes the view more declarative and minimizes the need to write updates in activities and fragments. If you prefer to do this in Java, use a library like Butter Knife to avoid boilerplate code and achieve better abstraction.

  • If the UI is complex, consider creating a Presenter class to handle changes to the UI. While this is usually not necessary, it may make the UI easier to test.

  • Do not reference the View or Activity context in the ViewModel. Because if the ViewModel outlives the Activity (in the case of configuration changes), the Activity will leak and not be properly recycled.

conclusion

All in all, Lifecycle has something to recommend it. Compared to other architectural components, Lifecycle is simpler and more independent (in fact, it tastes better with other components).

The purpose of this article is to analyze the principles of the Lifecycle framework related classes. Rather than delving deeply into each line of the source code for Lifecycle, I will attempt to write a detailed source code analysis if I have the opportunity.

Reference & Thanks

Lifecycle Aware Components source code analysis @ Chaosleong

Android Architecture Component I — Lifecycle @ShymanZhu

— — — — — — — — — — — — — — — — — — — — — — — — — – advertising line — — — — — — — — — — — — — — — — — — — — — — — — — — — — — –

series

Create the best series of Android Jetpack blogs:

  • A detailed analysis of the official Android architecture component Lifecycle
  • Android’s official architecture component ViewModel: From the past to the present
  • LiveData, the official Android architecture component: Two or three things in the Observer pattern area
  • Paging: The design aesthetics of the Paging library, an official Android architecture component
  • Official Android architecture component Paging-Ex: Adds a Header and Footer to the Paging list
  • Official Architecture component of Android Paging-Ex: reactive management of list states
  • Navigation: a handy Fragment management framework
  • DataBinding-Ex is an official Architecture component for Android

Jetpack for Android

  • Open source project: Github client implemented by MVVM+Jetpack
  • Open source project: Github client based on MVVM, MVI+Jetpack implementation
  • Summary: Using MVVM to try to develop a Github client and some thoughts on programming

About me

If you think this article is of value to you, please feel free to follow me at ❤️ or on my personal blog or Github.

If you think the writing is a little bit worse, please pay attention and push me to write a better writing — just in case I do someday.

  • My Android learning system
  • About article correction
  • About Paying for Knowledge