[Lifecycle with Jetpack on the back] Everything is based on Lifecycle, obscure and great use

[Lifecycle with Jetpack on the back] Everything is based on Lifecycle, obscure and great use

Series of articles

[Jetpack on the back] Dependency and transfer relationship of Jetpack's main components

[Jetpack on the back] Changes in the use of Activity and Fragment under AdroidX

[Fragment of Jetpack on back] Do you really know how to use Fragment? Fragment common problems and the new posture of using Fragment under androidx

[Fragment of Jetpack on the back] View Fragment life cycle AndroidX Fragment1.2.2 source code analysis from the source code point of view

[OnBackPressedDispatcher of Jetpack on the back] Fragment return stack preparation

[Fragment of Jetpack on the back] View the fragment return stack from the source code point of view with multiple return stack demos

[Jetpack on the back] The state that will never be lost androidx SaveState ViewModel-SaveState analysis

[ViewModel of Jetpack on the back] Even if you don t use MVVM, you must understand ViewModel-the functional boundary of ViewModel

Preface

There is a more important concept in Android: "life cycle". When I just graduated and went for an interview, I would always be asked questions like "the life cycle of the four major components". At the IO Conference in 2017, Google launched Lifecycle-Aware Components (Lifecycle Aware Components) to help developers organize better, lighter, and easy-to-maintain code

This article describes Lifecyclehow a simple analysis of lifecycle responsibilities and perceived activity and fragment, help you to Lifecycleknow there is a perceptual

Everything is based on Lifecycle

You don t understand the pain of manually managing the life cycle

Lu Xun once said: Everything is based on Lifecycle

Oh wrong

The view controller in Android has so many life cycles, so it is very important to handle the life cycle, otherwise it will cause memory leaks or even program crashes. The entire official documentation examples

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

    void start() {
        // 
    }

    void stop() {
        // 
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

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

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // activity  
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // activity  
    }
}
 

This example looks good. In a real application, you will still make too many calls to manage the UI and other components in response to the current state of the life cycle. Managing multiple components puts a lot of code in lifecycle methods, such as onStart() and onStop(), which makes them difficult to maintain

Moreover, there is no guarantee that the component will be started before the activity or fragment is stopped. If we need to perform long-running operations (such as certain configuration checks in onStart()), it may cause a race condition, where the onStop() method is completed before onStart(), thus making the component's lifetime exceed The required lifetime.

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

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

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            //  activity  
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}
 

If there are all components, they can perceive the external life cycle, release resources at the corresponding time, and can stop asynchronous tasks in time when the life cycle is missed.

We might as well think about what we should do if we realize this idea

Conventional thinking

1. let s sort out our needs

  • Internal components can perceive the external life cycle
  • Able to manage uniformly, make one modification and take effect everywhere
  • Ability to stop missed tasks in time

For Requirement 1, the observer mode can be used, and internal components can respond to changes in the external life cycle

For requirement 2, the code of the dependent component can be moved out of the life cycle method, and then moved into the component itself, so that you only need to modify the internal logic of the component

For requirement 3, observers can be removed at the right time

Observer mode

About observer mode, the first time I was in a more detailed understanding throw line object of a RxJava Android developers explain .

The requirement of the observer pattern is that the A object (observer) is highly sensitive to a certain change in the B object (observed), and needs to react at the moment when B changes. For example, a police officer who is popular in the news catches a thief, and the police need to arrest the thief when the thief reaches out to commit a crime. In this example, the police is the observer and the thief is the observed. The police need to keep an eye on the thief's every move to ensure that no moment is missed. This observer mode programs and real "observation" is slightly different, the viewer does not need to be time staring at the viewer (such as A does not need every 2ms to check the status of a B), instead of using the register (Register) or called subscription (Subscribe) way of telling the observer: I need your certain state, you have to notify me when it changes. A typical example in Android development is the click listener OnClickListener. For setting OnClickListener, it Viewis the observer, OnClickListenerthe observer, by both setOnClickListener()reached subscription relationship method. The moment the user clicks the button after subscribing, the Android Framework will send the click event to the registered one OnClickListener. Adopting such a passive observation method not only saves the resource consumption of repeatedly searching the state, but also can get the highest feedback speed. Of course, this is also due to the fact that we can customize the observers and the observed in our programs at will, and the police uncle obviously cannot ask the thief to "notify me when you commit a crime."

The mode of OnClickListener is roughly as follows:

The above description and pictures are from a RxJava Detailed Android developers

Therefore, when the life cycle of the life cycle component changes, the observer is told that the internal component can perceive the external life cycle

After introducing Lifecycle

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener() {
        ...
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());
 

Source code structure

This is the structure of Lifecycle , an abstract class. There are two enumerations inside, which represent "event" and "state" respectively. In addition, there are three methods to add/remove observers and get current state

Note that the order of enumeration in State here is meaningful, which will be described in detail later

Its implementation class is LifecycleRegistry , which can handle multiple observers

It internally holds the current state mState, LifecycleOwner and a custom list of observers, and at the same time overrides the method of adding/removing observers of the parent class

LifecycleOwner has the life cycle of Android. Custom components can use these events to handle life cycle changes without implementing any code in Activity or Fragment

LifecycleObserver , mark a class as LifecycleObserver. It does not have any methods, but depends on the method annotated by OnLifecycleEvent

LifecycleEventObserver can receive any lifecycle changes and dispatch them to the receiver.

If a class implements this interface and uses OnLifecycleEvent at the same time, the annotation will be ignored

DefaultLifecycleObserver , a callback interface used to monitor the status changes of LifecycleOwner .

If a class implements this interface and LifecycleEventObserver at the same time , DefaultLifecycleObserverthe method of will be called first , and then LifecycleEventObserver.onStateChanged (LifecycleOwner, Lifecycle.Event) will be called

Note: The use of DefaultLifecycleObserver needs to be introduced

implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

Simple source code analysis

activity life cycle processing

First of all, let s take a look at androidx.activity.ComponentActivity . This category has been mentioned many times in our series of articles. The first mention is in the [Jetpack on the back] state that will never be lost androidx SaveState ViewModel-SaveState analysis , interested Friends of you can take a look.

Most of the interfaces it implements have been discussed. Today we will take a look at LifecycleOwner

ActivityResultCaller was launched for activity 1.2.0-alpha02, aiming to unify onActivityResult, it will not be discussed here for now

Now that implements LifecycleOwnerthe interface, will rewrite getLifecycle () method

//androidx.activity.ComponentActivity.java
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

@Override
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}
 

Return of Lifecyclethe implementation class LifecycleRegistryinstance

The activity is the operation of life-cycle by ReportFragmentprocessing

//androidx.activity.ComponentActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ReportFragment.injectIfNeededIn(this);
    //...
}

//ReportFragment
public static void injectIfNeededIn(Activity activity) {
    if (Build.VERSION.SDK_INT >= 29) {
        //api 29    
        activity.registerActivityLifecycleCallbacks(
                new LifecycleCallbacks());
    }
    android.app.FragmentManager manager = activity.getFragmentManager();
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
        manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
        manager.executePendingTransactions();
    }
}
 

//ReportFragment.java
static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
    if (activity instanceof LifecycleRegistryOwner) {
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
        return;
    }
    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
        }
    }
}

private void dispatch(@NonNull Lifecycle.Event event) {
    if (Build.VERSION.SDK_INT < 29) {
        dispatch(getActivity(), event);
    }
}

@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);
}
@Override
public void onStop() {
    super.onStop();
    dispatch(Lifecycle.Event.ON_STOP);
}
@Override
public void onDestroy() {
    super.onDestroy();
    dispatch(Lifecycle.Event.ON_DESTROY);
}
 
//LifecycleCallbacks
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);
    }

    @Override
    public void onActivityPreStopped(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_STOP);
    }

    @Override
    public void onActivityPreDestroyed(@NonNull Activity activity) {
        dispatch(activity, Lifecycle.Event.ON_DESTROY);
    }
	//...
}
 

In the onCreate method of the activity, call the ReportFragmentstatic method injectIfNeededIn(). And internally, if the correct life cycle callback is directly registered on the device of api 29 and above, the lower version will start ReportFragment and handle the life cycle callback with the help of each life cycle of the fragment

Fragment life cycle processing

In the internal fragment, each lifecycle calling node handleLifecycleEventmethod

//Fragment.java
public Fragment() {
    initLifecycle();
}

private void initLifecycle() {
    mLifecycleRegistry = new LifecycleRegistry(this);
}

@Override
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}

void performCreate(Bundle savedInstanceState) {
    onCreate(savedInstanceState);
	mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);    
}

void performStart() {
    onStart();
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
}

void performResume() {
    onResume();
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);    
}

void performPause() {
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    onPause();
}

void performStop() {
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    onStop();
}

void performDestroy() {
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    onDestroy();
}
 

Lifecycle State size comparison

Lifecycle.State There is a isAtLeastmethod for determining the current state of the incoming state is not less than

//Lifecycle.State
public boolean isAtLeast(@NonNull State state) {
    return compareTo(state) >= 0;
}
 

The compareTo method of an enumeration is actually the order of the enumeration declarations to be compared

And the order of State is DESTROYED -> INITIALIZED -> CREATED -> STARTED -> RESUMED

If the passed state is STARTED, true is returned when the current state is STARTED or RESUMED, otherwise it returns false

LiveData will use this knowledge point

about me

I am Fly_with24