前言
学习记录系列是通过阅读学习《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 之后,在自定义组件内部便可以管理好其生命周期,不再需要担心组件的内存泄漏等问题了,组件使用起来也更加方便和安全