学习记录(2) - LifeCycle

前言

学习记录系列是通过阅读学习《Android Jetpack应用指南》对书中内容学习记录的Blog,《Android Jetpack应用指南》京东天猫有售,本文是学习记录的第二篇。


诞生

在 Android 应用程序开发中,解耦很大程序上表现为系统组件的生命周期与普通组件之间的解耦。普通组件在使用过程中通常需要依赖于系统组件的生命周期。有时候,我们不得不在系统组件的生命周期回调方法中,主动对普通组件进行调用或控制。因为普通组件无法主动获知系统组件的生命周期事件。

系统组件:指的是 Activity/Fragment、Service 和 Application
普通组件:为了让代码更容易管理和维护,通常会将代码按照功能或作用封装成组件

举例:我们经常需要在页面的 onCreate()方法中对组件初始化,在 onPause()方法中停止组件,而在页面的 onDestroy()方法中对组件进行资源回收工作。这样的工作非常烦琐,会让页面与组件之间的耦合度变高。但这些工作又不得不做,因为这可能会引发内存泄漏。
我们希望对自定义组件的管理,不依赖于页面生命周期的回调方法。同时,在页面周期发生变化时,也能及时收到通知。

简介

LifeCycle 可以帮助开发者创建可以感知生命周期的组件。这样,组件便能够在其内部管理自己的生命周期,从而降低模块间的耦合度,并降低内存泄漏发生的可能性。LifeCycle不只对 Activity/Fragment 有用,在 Service 和 Application 中也能大显身手。

使用LifeCycle解耦页面与组件

1.案例分析

需求:在用户打开某个页面时,获取用户当前的地理位置。
代码实现:

public class LifeCycleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);

        // 初始化位置管理器
        initLocationManager();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 开始获取用户的地理位置
        startGetLocation();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 停止获取用户的地理位置
        stopGetLocation();
    }
}

从以上代码可以看出,获取地理位置这个需求的实现,与页面的生命周期息息相关。如果要将获取地理位置这一功能独立成一个组件,那么生命周期是必须考虑在内的。我们不得不在页面生命周期的各个回调方法中,对组件进行通知,因为组件不能主动感知生命周期的变化。

2.LifeCycle的原理

Jetpack 提供了两个类:LifecycleOwner(被观察者)和 LifecycleObserver(观察者)。即通过观察者模式,实现对页面生命周期的监听。

在新版本的SDK包中,Activity已经默认实现了 LifecycleOwner 接口。LifecycleOwner 接口中只有一个getLifecycle(LifecycleObserver observer)方法,LifecycleOwner 正是通过该方法实现观察者模式的,

3.解决方案

利用LifecyCycle改写需求,将该功能从Activity中独立出去,在减少耦合度的同时,又不影响对生命周期的监听。

/**
 * 自定义组件,让组件实现LifecycleObserver接口。
 * 与获取地理位置相关的代码在该类中完成
 * 对于组件中那些需要在页面周期发生变化时得到通知的方法,我们需要在这些方法上使用@OnLifecycleEvent(Lifecycle.Event.On_XXX)标签进行标识。
 * 这样,当页面生命周期发生变化时,这些被标识过的方法便会被自动调用
 *
 * @author JinXin 2020/7/26
 */
public class MyLocationListener implements LifecycleObserver {

    private static final String TAG = "MyLocationListener";

    private OnLocationChangedListener onLocationChangedListener;

    public MyLocationListener(Context context, OnLocationChangedListener onLocationChangedListener) {
        this.onLocationChangedListener = onLocationChangedListener;

        // 初始化操作
        initLocationManager();
    }

    private void initLocationManager() {

    }

    /**
     * 当Activity执行onResume()方法时,该方法会被自动调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation: ");
        if (onLocationChangedListener != null) {
            onLocationChangedListener.onChanged(0,0);
        }
    }

    /**
     * 当Activity执行onPause()方法时,该方法会被自动调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void stopGetLocation() {
        Log.d(TAG, "stopGetLocation: ");
        if (onLocationChangedListener != null) {
            onLocationChangedListener.onChanged(0,0);
        }
    }

    /**
     * 当地理位置发生变化时,通过该接口通知调用者
     */
    public interface OnLocationChangedListener {

        /**
         * 地理位置发生变化
         * @param latitude 纬度
         * @param longitude 经度
         */
        void onChanged(double latitude, double longitude);

    }
}

在LifeCycleActivity中,只需要引用 MyLocationListener 即可,不再关心 Activity 生命周期变化对组件所带来的影响。生命周期的管理完全交给 MyLocationListener 内部自行处理。在 Activity 中要做的只是通过 getLifecycle().addObserver()方法,将观察者和被观察者绑定起来

public class LifeCycleActivity extends AppCompatActivity {

    private static final String TAG = "LifeCycleActivity";

    private MyLocationListener myLocationListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);
        // 使用Lifecycle感知生命周期
        // 自定义组件MyLocationListener,该组件实现LifeCycleObserver接口。
        // 获取地理位置相关的代码在该组件中完成
        myLocationListener = new MyLocationListener(this, (latitude, longitude) -> {

            // 展示收到的位置信息
            Log.d(TAG, "onChanged: " + latitude + " " + longitude);
        });

        // 将观察者与被观察者绑定
        getLifecycle().addObserver(myLocationListener);
    }
}


使用LifecycleService 解耦Service组件

1.LifecycleService 基本介绍

为了便于对 Service 生命周期的监听,达到解耦 Service 与组件的目的, Android 提供了一个名为 LifecycleService 的类。该类继承自 Service,并实现了 LifecycleOwner 接口。

2.LifecycleService 的具体使用方法

1.首先,需要在 app 的 build.gradle 文件中添加相关依赖

dependencies {
    // 添加lifecycle相关依赖
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

2.创建 MyService 类并继承自 LifecycleService ,LifecycleService 是 Service 的直接子类,使用和普通 Service 没有差别

public class MyService extends LifecycleService {

    private MyServiceObserver myServiceObserver;

    public MyService() {

        myServiceObserver = new MyServiceObserver();
        // 将观察者和被观察者绑定
        getLifecycle().addObserver(myServiceObserver);
    }
}

Service 记得要在 AndroidManifest.xml 中注册

3.创建 MyServiceObserver 类,该类需要实现 LifecycleObserver 接口

public class MyServiceObserver implements LifecycleObserver {

    private static final String TAG = "MyServiceObserver";

    /**
     * 当Service的onCreate()方法被调用时,该方法会被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void startGetLocation() {
        Log.d(TAG, "startGetLocation: 开始获取地理位置");
    }

    /**
     *  当Service的onDestroy()方法被调用时,该方法会被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void stopGetLocation() {
        Log.d(TAG, "stopGetLocation: 停止获取地理位置");
    }
}

4.在 Activity 中控制 Service 的启动和停止

public class LifecycleServiceActivity extends AppCompatActivity {

    private static final String TAG = "LifecycleServiceActivit";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle_service);

        findViewById(R.id.btn_start_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 启动服务
                Intent intent = new Intent(LifecycleServiceActivity.this, MyService.class);
                startService(intent);
            }
        });

        findViewById(R.id.btn_stop_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 停止服务
                Intent intent = new Intent(LifecycleServiceActivity.this, MyService.class);
                stopService(intent);
            }
        });
    }
}

5.通过 LogCat 中的日志可以看出,随着 Service 生命周期的变化,MyServiceObserver 中带有 @onLifecycleEvent 标签的方法被自动调用了。这样便实现了组件对 Service 生命周期的监听。

2020-10-21 22:52:25.471 20670-20670/com.jinxin.jetpacktest D/MyServiceObserver: startGetLocation: 开始获取地理位置
2020-10-21 22:52:26.925 20670-20670/com.jinxin.jetpacktest D/MyServiceObserver: stopGetLocation: 停止获取地理位置

6.总结

当 Service 的生命周期发生变化时,不再需要主动对组件对组件进行通知,组件能够在其内部自动管理好生命周期所带来的变化。LifecycleService 很好地实现了组件与 Service 之间的解耦。


使用 ProcessLifecycleOwner 监听应用程序的生命周期

1.ProcessLifecycleOwner 存在的意义

监听整个应用程序的生命周期情况

2.ProcessLifecycleOwner 的具体使用方法

1.首先,需要在 app 的 build.gradle 文件中添加相关依赖

dependencies {
    // 添加lifecycle相关依赖
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

2.ProcessLifecycleOwner 的本质也是观察者模式。由于观察的是整个应用程序,因此,需要在 Application 中进行相关代码的编写。

public class MyApplication extends Application{

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

        // ProcessLifecycleOwner是针对整个应用程序的监听,与Activity数量无关
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new ApplicationObserver());
    }
}

3.定义一个名为 ApplicationObserver 的类,让该类实现 LifecycleObserver 接口,已负责对应用程序生命周期的监听

/**
 * 负责对应用程序生命周期的监听
 *
 * Lifecycle.Event.ON_CREATE 只会被调用一次,而Lifecycle.Event.ON_DESTROY永远不会被调用
 * 当应用程序从后台回到前台,或者应用程序被首次打开时,会依次调用Lifecycle.Event.ON_START和Lifecycle.Event.ON_RESUME
 * 当应用程序从前台回到后台(用户按下Home键或任务菜单键),会依次调用Lifecycle.Event.ON_PAUSE和Lifecycle.Event.ON_STOP
 * 
 * 需要注意的是,Lifecycle.Event.ON_START 和 Lifecycle.Event.ON_RESUME,这两个方法的调用会有一定的延后。
 * 这是因为系统需要为 “屏幕旋转,由于配置发生变化而导致 Activity 重新创建” 的情况预留一些时间。也就是说,系统需要保证当设备出现这种情况时,
 * 这两个事件不会被调用,因为当旋转屏幕时,你的应用程序并没有推到后台,它只是进入了横/竖屏模式而已
 * @author JinXin 2020/7/27
 */
class ApplicationObserver implements LifecycleObserver {

    private static final String TAG = "ApplicationObserver";

    /**
     * 在应用程序的整个生命周期中只会被调用一次
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void onCreate() {
        Log.d(TAG, "onCreate: ");
    }

    /**
     * 当应用程序在前台出现时被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onStart() {
        Log.d(TAG, "onStart: ");
    }

    /**
     * 当应用程序在前台出现时被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void onResume() {
        Log.d(TAG, "onResume: ");
    }

    /**
     * 当应用程序退出到后台时被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    private void onPause() {
        Log.d(TAG, "onPause: ");
    }

    /**
     * 当应用程序退出到后台时被调用
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onStop() {
        Log.d(TAG, "onStop: ");
    }

    /**
     * 永远不会被调用,系统不会分发调用ON_DESTROY
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void onDestroy() {
        Log.d(TAG, "onDestroy: ");
    }
}


总结

Lifecycle 组件存在的主要意义是帮助我们解耦,让自定义组件也能感受到生命周期的变化。有了 Lifecycle 之后,在自定义组件内部便可以管理好其生命周期,不再需要担心组件的内存泄漏等问题了,组件使用起来也更加方便和安全

你可能感兴趣的:(学习记录(2) - LifeCycle)