本文将介绍Architecture Components中的Lifecycle组件

Handling Lifecycles

android.arch.lifecycle 包提供了能够构建拥有 lifecycle-aware 能力的组件的类和接口。 lifecycle-aware 在这里是指能自动感知activity或者fragment生命周期,并随之自动调整自己行为的能力。

Android应用的大部分组件都是要么是系统自带生命周期的,要么框架管理的。如果无视这些,很有可能带来的后果是crash或者内存泄露。

举个例子:在activity中显示设备地址,通常的做法会将MyLocationListenerMyActivity的生命周期绑定在一起。

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
});
}

public void onStart() {
super.onStart();
myLocationListener.start();
}

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

尽管上面的代码看起来没问题,但是——onStart()以及 onStop() 中慢慢会积累越来越多的这种注册、反注册调用。

有时,也有可能components是在某个回调中starting,比如location observer start()在Activity onStop之后被调用,这意味着myLocationListener.start()会在stop之后重启。

class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;

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

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

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

下面就要开始推销android.arch.lifecycle

Lifecycle


Lifecycle 是一个状态类,主要维护了两个枚举值,来跟踪 component 的lifecycle

  • Event

Lifecycle和Framework派发,这些event注册到对应的activities 和fragments的回调事件

  • State

记录component 当前的生命周期状态

用图数据结构理解的话,status就是节点,而event是连接各个节点的边。

要想监控component的生命周期,只需要在对应方法上面添加相应annotations

public class MyObserver implements LifecycleObserver {
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}

+ @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
}
}
aLifecycleOwner.getLifecycle().addObserver(new MyObserver());

LifecycleOwner


LifecycleOwner 只是一个单一方法接口类,用于表明这个类有个Lifecycle状态类。LifecycleOwner通过getLifecycle() 方法将activities 或 fragments抽出来。任何类都可以实现LifecycleOwner,没有限制。

Note: 在 alpha 阶段, FragmentAppCompatActivity还没有实现这个接口。目前可以用LifecycleActivityLifecycleFragment 替代。 release后,support库中的 fragments and activities 默认会实现 LifecycleOwner

下面修改例子中的MyLocationListener 继承自LifecycleObserver

+ class MyActivity extends LifecycleActivity {
private MyLocationListener myLocationListener;

public void onCreate(...) {
+ myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
// update UI
});
Util.checkUserStatus(result -> {
if (result) {
+ myLocationListener.enable();
}
});
}
}

+ class MyLocationListener implements LifecycleObserver {
private boolean enabled = false;
public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
...
}

+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {
if (enabled) {
// connect
}
}

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

+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// disconnect if connected
}
}

注意上面的

if(lifecycle.getState().isAtLeast(STARTED))

我们有能力在回调特定方法时,随时检查lifecycle当前的状态。

比如 Fragment 有一个著名crash:在Activity state save后调用fragment transaction,就可以通过这种方式避免。good :)

LocationListener现在已经能能感知到Activity的生命周期变化了。既不需要我们注册,也不需要注销,all is done。

LocationListener这种能和Lifecycle一起工作的类被称为 lifecycle-aware components

LiveData 就是一种 lifecycle-aware component。 结合 LiveDataViewModel可以在Android Lifecycle的基础上实现UI界面数据的更新。

Lifecycle的最佳实践


  • 不要在 UI controllers 中直接获取数据 (activities and fragments),使用ViewModel获取数据, 再通过 LiveData把数据映射到UI上。
  • 推荐写数据驱动的UI,而 UI controller的职责是在数据改变时更新UI, 或者将用户交互通知到ViewModel
  • 将数据逻辑限制在 ViewModel 类中。但是获取数据(比如从网上)不是 ViewModel该做的事。 ViewModel 应该是 UI controller 和其他模块的连接器。比如ViewModel调用其他的模块去获取数据然后把结果传给UI controller。
  • 通过 Data Binding 来保证 view 和 UI controller 之间接口的干净。最终目的是让 view 的变动引起的 activities 代码改动最小化。
  • 如果UI足够复杂,可以考虑抽出一个Presenter来处理UI更新。虽然有点大材小用,但是可以让view更容易测试.
  • 永远不要在ViewModel中直接引用 View 或者 Activity context。记住 ViewModel在Activity重建(configuration changes)后会恢复为同一个实例,那么之前引用的context就会内存泄露。

附录


在自定义 activities 或 fragments中实现LifecycleOwner

其实不用继承LifecycleFragment 或者 LifecycleActivity,只要自定义 fragment 或者 activity 实现了LifecycleRegistryOwner 接口,它就可以被看为LifecycleOwner

public class MyFragment extends Fragment implements LifecycleRegistryOwner {
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}

如果你想让一个自定义类成为 LifecycleOwner, 你可以用LifecycleRegistry, 只不过你得自己负责派发生命周期事件到自定义类。而对于实现了LifecycleRegistryOwner的fragments 和 activities ,这个派发动作是自动完成的。