Jetpack-生命周期组件库Lifecycle

Jetpack生命周期组件#

本文主要针对lifecycle引入的背景以及lifecycle比传统监听生命周期优势做了详细对比,也介绍了具体用法。

问题引入#

当组件需要具备生命周期感知能力时,我们传统写法如下

  • 定义接口类、定义对象,在Activity、Fragment的生命周期手动回调接口
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
39
class MyLocationListener {
public MyLocationListener(Context context, Callback callback) {
// ...
}

void start() {
// connect to system location service
}

void stop() {
// disconnect from system location service
}
}
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;

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

@Override
public void onStart() {
super.onStart();
Util.checkUserStatus(result -> {
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start();
}
});
}

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

传统写法具备如下缺点

  • 太多组件需要维护生命周期状态,会写太多的生命周期接口回调

  • 组件的回调不一定会按照Activity生命周期的调用顺序执行;Activitiy的onStart中有异步任务,可能出现组件#onStop先执行,组件#onstart后执行的情况,造成内存泄漏

如这么写,会有很明显的问题:

  1. 每个子组件我们都需要要将myLocationListener#start、#stop调用一遍,如果有十几个组件,代码写出来很酸爽;
  2. myLocationListener#start是异步的,可能会晚于myLocationListener#stop执行
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
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;

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

@Override
public void onStart() {
super.onStart();
Util.checkUserStatus(result -> {
// what if this callback is invoked AFTER activity is stopped?
if (result) {
myLocationListener.start();
}
});
}

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

androidx.lifecycle 软件包提供的类和接口可帮助您以弹性和隔离的方式解决这些问题。

本文主要围绕生命周期感知型组件展开,讲解以这些组件的用法。

快速集成#

lifecycle包提供的组件支持2种依赖方式,下面两种依赖方式任选一种

1
2
3
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
// 按需使用--如果想使用DefaultLifecycleObserver
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"

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
dependencies {
def lifecycle_version = "2.5.0-rc02"
def arch_version = "2.1.0"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

// Annotation processor
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

// optional - helpers for implementing LifecycleOwner in a Service
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"

// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
}

databinding需要额外修改gradle文件

1
2
3
4
5
6
7
android {
...
dataBinding {
enabled = true
}
}

LifeCycle#

定义#

存储Activity、Fragment生命周期状态信息的类

用途#

弹性和隔离的方式解决传统写法的问题

基本用法#

定义lifecycle对象#

这个实现类就有一点Viewmodel的影子,注意比较与viewmodel的相似之处

写一个类,继承DefaultLifecycleObserver,有以下几点需要注意

  • 按需复写回调,如onStart等;
  • 在构造函数里接收Lifecycle对象,用于判断生命周期状态
  • MyLocationListener用于处理数据,每个异步方法执行前都要判断一下lifecycle.getCurrentState()的值,避免内存泄漏、crash
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
public class MyLocationListener implements DefaultLifecycleObserver {
private UpdateUiCallBack callback;
private Lifecycle lifecycle;
private boolean enabled = false;

public MyLocationListener(Context context, Lifecycle lifecycle, UpdateUiCallBack callback) {
this.lifecycle = lifecycle;
this.callback = callback;
}

@Override
public void onStart(LifecycleOwner owner) {
if (enabled) {
// connect
}
}

public void enable() {
enabled = true;
if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
// connect if not connected
}
}

@Override
public void onStop(LifecycleOwner owner) {
// disconnect if connected
}
}

初始化#

Activity主要做2件事情

  1. 实现LifecycleOwner接口

  2. 实例化两个关键的对象

  • LifecycleRegistry,Lifecycle的实现类,用于设置Activity#Lifecycle事件的值
  • MyLocationListener用于执行数据管理
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class TestLifecycleActivity extends AppCompatActivity implements LifecycleOwner {
/**
* 传统写法
*/
private NormalListener normalListener;
/**
* lifecycle写法
*/
private LifecycleRegistry lifecycleRegistry;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_lifecycle);
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.markState(Lifecycle.State.CREATED);
normalListener = new NormalListener(this, new UpdateUiCallBack());
MyLocationListener myLocationListener = new MyLocationListener(this, getLifecycle(), new UpdateUiCallBack());
}

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

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

@Override
protected void onStop() {
super.onStop();
normalListener.onStop();
}

@Override
protected void onResume() {
super.onResume();
lifecycleRegistry.markState(Lifecycle.State.RESUMED);
}

@Override
protected void onDestroy() {
super.onDestroy();
lifecycleRegistry.markState(Lifecycle.State.DESTROYED);
}
}

  • 可以看到Activity#getLifecycle() 返回的是我们新创建的lifecycleRegistry

  • 创建LifecycleRegistry对象的时候,传入了实现LifecycleOwner接口的Activity实例化对象

  • 通过markState设置LifecycleOwner所处的生命周期

设置事件#

STARTED\RESUMED\DESTROYED同理,设置方式参考下图

生命周期状态示意图

1
lifecycleRegistry.markState(Lifecycle.State.CREATED);

最佳实践#

参考本文相关的其他文章

  • LifeCycle
  • ViewModel
  • Livedata
  • Databinding

场景#

  • 停止和开始视频缓冲:应用销毁后,自动停止缓冲;配置发生变化后,缓冲数据仍然可用;在后台时刻缓冲数据,并不更新ui,返回前台后,观察者收到最新数据变化,更新UI即可
  • 开始和停止网络连接:前台时候数据实时更新,后台暂停网络更新
  • 暂停和恢复动画可绘制资源:后台暂停动画绘制资源,前台恢复绘制所需的资源

后续:Jetpack包对MVVM的支持#

疑问:

  1. MVVM与MVC、MVP之争

  2. 下一代MVI?

  3. https://www.gwtproject.org/articles/mvp-architecture.html

点击查看
-------------------本文结束 感谢您的阅读-------------------