1. Case study

Consider a common requirement to get a user’s current geographic location when they open a page. Faced with this requirement, we usually write code like this.

package com.kf.ui;

import android.os.Bundle;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

/** * TODO Description File Description **@author nomi
 * @package com.kf.ui
 * @date2021/7/22-10:56 * / in the morning
public class LocationActivity extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Initialize the location manager
        initLocationManager();
    }

    /** * Initialize the positioning operation */
    private void initLocationManager(a) {
        Log.d("Location"."initLocationManager");
    }


    @Override
    protected void onResume(a) {
        super.onResume();
        // Start to get the user's location
        startGetLocation();
    }

    @Override
    protected void onPause(a) {
        super.onPause();
        // Stop getting the user's location
        stopGetLocation();
    }

    /** * This method is automatically called when the Activity executes the onResume() method
    private void startGetLocation(a) {
        Log.d("Location"."startGetLocation");
    }

    /** * This method is automatically called when the Activity executes onPause()
    private void stopGetLocation(a) {
        Log.d("Location"."stopGetLocation"); }}Copy the code

As you can see from the code above, the implementation of the requirement to get the location is closely related to the life cycle of the page. The lifecycle must be taken into account if we want to have the ability to get the location as a separate component. We have to notify the component in the various callback methods of the page lifecycle because the component is not actively aware of lifecycle changes.

2. How LifeCycIe works

How does LifeCycle solve this problem? Jetpack provides us with two classes: LifecycleOwner and LifecycleObserver. That is, through the observer mode, the life cycle of the page is monitored. By looking at the SupportActivity source code, you can see that the new SDK package implements the LifecycleOwner interface by default. Only one getLifecycle LifecycleOwner interface (LifecycleObserverobserver) method, it is through the LifecycleOwner method realizes the observer pattern. The following is an example of source code.As you can see from the above source code, SupportActivity already implements the part of the code that the observer should implement for us. Therefore, we don’t need to implement this code. When we want to listen to the lifecycle of an Activity, all we need to do is implement the observer part of the code by having our custom component implement the LifecycleObserver interface. This interface has no interface methods and does not require any specific implementation.

The code for SupportActivity and ComponentActivity is not much different:


public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner.ViewModelStoreOwner.HasDefaultViewModelProviderFactory.SavedStateRegistryOwner.OnBackPressedDispatcherOwner {
static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
private final SavedStateRegistryController mSavedStateRegistryController =
        SavedStateRegistryController.create(this);

// Lazily recreated from NonConfigurationInstances by getViewModelStore()
private ViewModelStore mViewModelStore;
private ViewModelProvider.Factory mDefaultFactory;

private final OnBackPressedDispatcher mOnBackPressedDispatcher =
        new OnBackPressedDispatcher(new Runnable() {
            @Override
            public void run(a) {
                ComponentActivity.super.onBackPressed(); }});@LayoutRes
private int mContentLayoutId;

/**
 * Default constructor for ComponentActivity. All Activities must have a default constructor
 * for API 27 and lower devices or when using the default
 * {@link android.app.AppComponentFactory}.
 */
public ComponentActivity(a) {
    Lifecycle lifecycle = getLifecycle();
    //noinspection ConstantConditions
    if (lifecycle == null) {
        throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                + "constructor. Please make sure you are lazily constructing your Lifecycle "
                + "in the first call to getLifecycle() rather than relying on field "
                + "initialization.");
    }
    if (Build.VERSION.SDK_INT >= 19) {
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_STOP) {
                    Window window = getWindow();
                    finalView decor = window ! =null ? window.peekDecorView() : null;
                    if(decor ! =null) { decor.cancelPendingInputEvents(); }}}}); } getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                if(! isChangingConfigurations()) { getViewModelStore().clear(); }}}});if (19 <= SDK_INT && SDK_INT <= 23) {
        getLifecycle().addObserver(new ImmLeaksCleaner(this)); }}Copy the code

3. Solutions

Now, let’s rewrite this requirement using LifeCycle. Our goal is to separate this functionality from the Activity, reducing coupling without affecting the monitoring of the life cycle. 1. Write a class called LocationLifeCycleListener. This class is our custom component, which we need to implement the LifecycleObserver interface. The code associated with getting the geolocation is done in this class. Methods in the component that need to be notified of changes in the page Lifecycle need to be identified with the @onlifecycleEvent (lifecyc.event.on_xxx) tag on these methods. In this way, these identified methods are automatically invoked when the page lifecycle changes. As shown below.

package com.kf.ui.util;

import android.app.Activity;
import android.util.Log;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

/** * TODO Description File Description **@author nomi
 * @package com.kf.ui.util
 * @date2021/7/22 - they * / in the morning
public class LocationLifeCycleListener implements LifecycleObserver {

    public LocationLifeCycleListener(Activity context, OnLocationChangedListener onLocationChangedListener) {
        // Initialize the location manager
        initLocationManager();
    }

    /** * Initialize the positioning operation */
    private void initLocationManager(a) {
        Log.d("Location"."initLocationManager");
    }

    /** * This method is automatically called when the Activity executes the onResume() method
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void startGetLocation(a) {
        Log.d("Location"."startGetLocation");
    }

    /** * This method is automatically called when the Activity executes onPause()
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    private void stopGetLocation(a) {
        Log.d("Location"."stopGetLocation");
    }


    public interface OnLocationChangedListener {
        /** * Obtain location information **@param latitude
         * @param longitude
         */
        void onChanged(double latitude, double longitude); }}Copy the code

In MainActivity, you just reference MyLocationListener, and you don’t have to worry about the impact of Activity lifecycle changes on that component. Lifecycle management is completely handled internally by MyLocationListener. All that needs to be done in the Activity is to bind the observer to the observed via the getLifecycle().addobServer () method as shown below.

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

/** * TODO Description File Description **@author nomi
 * @package com.kf.ui
 * @date2021/7/22-10:56 * / in the morning
public class LocationLifecycleActivity extends AppCompatActivity {

    private LocationLifeCycleListener locationLifeCycleListener;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        locationLifeCycleListener = new LocationLifeCycleListener(this.new LocationLifeCycleListener.OnLocationChangedListener() {
            @Override
            public void onChanged(double latitude, double longitude) {
                // Display the received location information}});// Bind the observer to the observedgetLifecycle().addObserver(locationLifeCycleListener); }}Copy the code

LifeCycle perfectly solves the problem of component dependency on the page LifeCycle, allowing components to manage their own LifeCycle rather than having to manage it within the page. This greatly reduces code coupling, improves component reuse, and eliminates memory leaks caused by careless page lifecycle management, which is very helpful in the case of large projects.

In addition to activities, fragments also implement the LifecycleOwner interface by default in the new SDK. Therefore, the above example applies to fragments as well. The source code for Fragment is shown below.

From The Android Jetpack App Guide by Ye Kun item.jd.com/12684819.ht…