Jetpack之生命周期感知组件-Lifecycle使用篇

2021年02月25日 99 字 Jetpack


前言

什么是生命周期感知组件?

生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。这些组件有助于您写出更有条理且往往更精简的代码,这样的代码更易于维护。

Lifecycle是什么?

Lifecycle 是一个类,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态。

它所解决的痛点问题是什么?

在 Android 框架中定义的大多数应用组件都存在生命周期。生命周期由操作系统或进程中运行的框架代码管理。它们是 Android 工作原理的核心,应用必须遵循它们。如果不这样做,可能会引发内存泄漏甚至应用崩溃。

【本系列文章(JAVA/KOTLIN)演示案例均存储在github存储库ArchitecturalComponentExample中】

使用Lifecycle的意义

说起Activity生命周期,不难想到Application有个方法registerActivityLifecycleCallbacks()可以注册生命周期回调, 且在Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q时的Activity也扩展了这个方法,获取activity生命周期状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
Log.i("loglog", "onActivityCreated");
}

@Override
public void onActivityStarted(@NonNull Activity activity) {
Log.i("loglog", "onActivityStarted");
}

@Override
public void onActivityResumed(@NonNull Activity activity) {
Log.i("loglog", "onActivityResumed");
}

@Override
public void onActivityPaused(@NonNull Activity activity) {
Log.i("loglog", "onActivityPaused");
}

@Override
public void onActivityStopped(@NonNull Activity activity) {
Log.i("loglog", "onActivityStopped");
}

@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {
Log.i("loglog", "onActivitySaveInstanceState");
}

@Override
public void onActivityDestroyed(@NonNull Activity activity) {
Log.i("loglog", "onActivityDestroyed");
}
});

同样的,我们也可以在Activity中单纯使用生命周期回调onCreate()onResume()等来实现生命周期监听。

具体案例参考官方文档

我们不难发现这样写存在这样一些问题:

  • 生命周期管理集中,且并非所有生命周期回调我们都要用
  • 若同一生命周期回调中要做多个功能,同一个回调方法中代码量将会很大,这将带来巨大的维护成本
  • 无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 onStart() 中的某种配置检查)时尤其如此。这可能会导致出现一种竞态条件,在这种条件下,onStop() 方法会在 onStart() 之前结束,这使得组件留存的时间比所需的时间要长。

Lifecycle 可以为你的每一个功能提供独立的生命周期观察者,做到功能代码与界面(Activity/Fragment)更小的耦合,且每一个功能的生命周期观察者都可以被复用,功能组件的抽离也能为你的程序带来更强大的扩展性。

使用Lifecycle

引入依赖

文档编写时,稳定依赖版本为2.2.0 ,下一候选预览版为2.3.0-rc01,引入时请检查官方文档推荐版本,以当前稳定版为主要选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
dependencies {
def lifecycle_version = "2.3.0"
def arch_version = "2.1.0"

// ViewModel支持
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData支持
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// 仅Lifecycles (不包括 ViewModel 和 LiveData支持)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

// 保存ViewModel的状态模块
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

// 注解处理器
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// 另外——如果使用Java8,使用下面的代码代替lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

// 可选——在服务中实现LifecycleOwner的助手
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

// 可选- ProcessLifecycleOwner为整个应用程序过程提供一个生命周期
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

// 可选- ReactiveStreams支持LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"

// 可选的- LiveData的测试助手
testImplementation "androidx.arch.core:core-testing:$arch_version"
}

以上依赖库并非所有内容均需要引入,请根据实际需求引入对应依赖。

例如,你单纯的想使用Lifecycle的生命周期管理能力,你可以这样引入依赖:

1
2
3
4
5
6
7
8
9
dependencies {
def lifecycle_version = "2.3.0"

// 单纯生命周期组件
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

// 负责进程(应用)的生命周期
implementation 'androidx.lifecycle:lifecycle-process:$lifecycle_version'
}

LifecycleObserver

编写你的LifecycleObserver 观察者,并将其添加到界面组件的LifecycleOwner观察队列(集合)中
,即可完成对界面组件生命周期的观察,你可以在你的LifecycleObserver 定义你感兴趣的生命周期事件,例如你需要控制相机在亮/息屏时开启或停止,你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CameraLifecycleObserver implements LifecycleObserver {

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void initCamera(){
Log.i("loglog", "ON_CREATE 初始化相机");
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void openCamera() {
Log.i("loglog", "ON_RESUME 打开相机");
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void closeCamera() {
Log.i("loglog", "ON_PAUSE 关闭相机");
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy(){
Log.i("loglog", "ON_DESTROY 销毁资源");
}
}

当然,若你还想利用其他生命周期,或者主动获取组件的生命周期,你或可以将生命周期组件传入CameraLifecycleObserver组件中,通过其获取当前生命周期:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CameraLifecycleObserver implements LifecycleObserver {

private Lifecycle mLifecycle = null;
// 当然,此处也可以传递 LifecycleOwner 以及其他类型参数
public CameraLifecycleObserver(Lifecycle lifecycle){
mLifecycle = lifecycle;
}

// 你应当在合适的时机调用方法体中的两个API,而并非一定要在 ON_ANY 的时刻调用
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onAny(){
// 获取当前状态
Lifecycle.State currentState = mLifecycle.getCurrentState();
// 至少已经执行onStart了
boolean hasStarted = currentState.isAtLeast(Lifecycle.State.STARTED);
}
}

组件实现LifecycleOwner

完成了观察者的编写,我们可以将观察者的实例传递给LifecycleOwner,而关于Lifecycleowner你可能存在以下两种情况:

  • 你使用了Androidx支持库,且版本 >=26.1.0, Fragment 和 Activity 已实现 LifecycleOwner 接口,此处主要指继承自ComponentActivity及其子类的Activity和继承自androidx.fragment.app.Fragment的Fragment。
  • 其他情况,你需要自行实现LifecycleOwner ,并重写getLifecycle()方法,并手动分发你需要的生命周期:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyActivity extends Activity implements LifecycleOwner {
private LifecycleRegistry lifecycleRegistry;

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

lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
}

@Override
public void onStart() {
super.onStart();
lifecycleRegistry.markState(Lifecycle.State.STARTED);
}

@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
}

将观察者交给LifecycleOwner

当你拥有LifecycleOwner对象后,你就可以将你实现的观察者LifecycleObserver 交给它了,当有生命周期变化事件发生,LifecycleObserver将会通知你的LifecycleOwner。

1
getLifecycle().addObserver(new CameraLifecycleObserver(...params));

让我们来看一下其执行结果:

1
2
3
4
5
6
7
8
9
I/loglog: ON_CREATE 初始化相机
I/loglog: onActivityStarted
I/loglog: onActivityResumed
I/loglog: ON_RESUME 打开相机
I/loglog: ON_PAUSE 关闭相机
I/loglog: onActivityPaused
I/loglog: onActivityStopped
I/loglog: ON_DESTROY 销毁资源
I/loglog: onActivityDestroyed

为进程添加生命周期事件

如果你想监听应用前后台变化,你可以看下此小节。
以往的,观察应用是否前台,你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean inAppOnForeground(Context context) {
try {
ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
String packageName = context.getPackageName();
if (activityManager != null) {
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (packageName.equals(appProcess.processName)
&& appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

这样你只能知道应用是否前台,但无法知道它什么时候进入前台,什么时候进入后台,如果你恰好需要知道应用何时进入后台执行某项工作,这样做可能并不适合。当然你也可以通过Application.registerActivityLifecycleCallbacks()监听activity的启动和退出,为其启动和退出计数,当退出时计数为0则可视作应用后台,当启动时计数为1则可视做应用前台,emmmm,想想我就觉得工作量挺大~

让我们看看使用Lifecycle如何简单做到这件事情吧(需引入依赖androidx.lifecycle:lifecycle-process:$last_version):

  • 编写生命周期观察者
  • 为你的Application添加生命周期观察者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ProcessLifecycleObserver implements LifecycleObserver {
// 标记前后台状态的一种方案
private boolean isForeground = false;

@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onForeground() {
Log.i("loglog", "onForeground: ON_START");
isForeground = true;
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onBackground() {
Log.i("loglog", "onBackground: ON_STOP");
isForeground = false;
}
// 获取前后台状态的一种方案
public boolean isForeground() {
return isForeground;
}

}

public class MyApplication extends Application {

private ProcessLifecycleObserver observer;

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

observer = new ProcessLifecycleObserver();
ProcessLifecycleOwner.get().getLifecycle().addObserver(observer);
}
// 获取前后台状态的一种方案
public boolean isForeground() {
return observer.isForeground();
}
}

这样就简单的完成了应用前后台切换的监听,以及前后台状态的查询了~

生命周期感知型组件的最佳做法

如需了解生命周期感知组建的最佳做法,请点击 官方文档 获得详细内容

关于Lifecycle 与LiveData等jetpack组件配合使用,将在架构组件基础使用系列完结后一并编写介绍,在此之前,请参考官方文档