使用Lifecycle处理生命周期
大多数Android Framework中的app组件都有自己的生命周期。这些生命周期由操作系统或者运行在你的进程中的框架代码所管理。它们是Android系统工作原理的核心,你必须遵守。否则就由可能会导致内存泄漏甚至崩溃。
假设我们有一个显示设备所处位置的activity。常见的实现方式大致如下:
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();
}
}
虽然这个例子看起来是正确的,但在真实的app中,最终可能会出现超多类似这样的调用,而且 onStart() 和 onStop()也会变得非常大。
此外,有些控件不能直接在onStart()中启动。要是在开始定位监听之前需要检查一些配置怎么办?完全有可能在某些情况下activity停止之后检查才完成,也就是说myLocationListener.start() 可能会在myLocationListener.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();
}
}
Lifecycle提供了一套帮助你以一种灵活独立的方式处理这些问题的类。
Lifecycle
Lifecycle 是一个持有组件(比如 activity 或者 fragment)生命周期状态信息的类,并且允许其它对象观察这个状态。
Lifecycle 主要使用两个枚举来跟踪相关组件的生命周期状态。
Event
由framework和Lifecycle类发出的生命周期事件。这些事件对应Activity和Fragment中的回调事件。
译注:
Lifecycle.Event | ON_ANY An Event constant that can be used to match all events. |
Lifecycle.Event | ON_CREATE Constant for onCreate event of the LifecycleOwner. |
Lifecycle.Event | ON_DESTROY Constant for onDestroy event of the LifecycleOwner. |
Lifecycle.Event | ON_PAUSE Constant for onPause event of the LifecycleOwner. |
Lifecycle.Event | ON_RESUME Constant for onResume event of the LifecycleOwner. |
Lifecycle.Event | ON_START Constant for onStart event of the LifecycleOwner. |
Lifecycle.Event | ON_STOP Constant for onStop event of the LifecycleOwner. |
State
Lifecycle对象获取到的组件当前的状态。
一个类可以通过在它的方法中添加注解来管理组件的lifecycle。
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 是一个只有单个方法的接口,代表类具有生命周期。这个唯一的方法是getLifecycle(),必须实现。
这个类把 Lifecycle从各个生命周期组件(比如Activity和Fragmennt)中抽象出来,从而写一个两者都适用的组件。任何一个自定义的application类都可以实现 LifecycleOwner 接口。
注:因为Lifecycle项目还处于alpha阶段,Fragment 和 AppCompatActivity 类还不能实现它(因为我们不能让一个稳定的控件依赖于一个不稳定的API)。在Lifecycle 稳定之前,我们提供 LifecycleActivity 和 LifecycleFragment 方便大家使用。当Lifecycle项目正式发布之后,支持库中的fragment和Activity将实现 LifecycleOwner ;届时LifecycleActivity 和 LifecycleFragment 将被视作过时的类。 可以参考 自定义Activity或者Fragment实现LifecycleOwner。
对于前面的例子,我们可以把MyLocationListener类写成 LifecycleObserver,在onCreate中使用我们的Lifecycle初始化之,然后就不用再管他了。这让MyLocationListener类可以自给自足,在必要的时候自己做清理。
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();
}
});
}
}
常见的用例就是在 Lifecycle 不合适的时候不触发某个回调。比如,如果回调在activity回收状态之后运行fragment transaction的话,会出现崩溃,因此我们绝对不会想触发那个回调。
为了让这种用例处理起来简单, Lifecycle 允许其它的对象查询当前的状态。
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
}
}
这样实现之后,我们的LocationListener类就完全有了生命周期意识;它可以无需activity管理,自己做初始化和清理的工作。如果我们需要在其它的activity或者fragment中使用这个LocationListener,我们只需要初始化它酒醒了。所有的清理工作都由它自己完成。
可以和Lifecycle一起工作的类我们称之为有生命周期意识的控件。我们建议那些提供了需要和Android生命周期打交道的类的库最好提供有生命周期意识的控件,这样它们的用户就能轻松的集成这些类,而不是在客户端手动管理生命周期。
LiveData 就是一个有生命周期意识的控件的例子。使用LiveData 和 ViewModel 可以让数据部署到UI更简单。
Lifecycle最佳实践
-
尽可能保持UI控制器(Activity和Fragment)的简洁。它们不应该去获取数据,而是使用ViewModel 来做这个工作,然后观察LiveData 把变化反应给view。
-
尝试写数据驱动的UI,UI controller的职责是在数据改变的时候更新view,或者把用户的操作通知给ViewModel。
-
把数据逻辑放在ViewModel 类中。ViewModel的角色是UI控制器与app其余部分的桥梁。不过要注意,ViewModel的职责并不是获取数据(比如,从网络)。相反 ViewModel应该调用合适的控件去做这件事情,然后把结果提供给UI控制器。
-
使用 Data Binding来让view和UI控制器之间的接口保持干净。这可以让你的view更加声明式同时最小化Activity和Fragment中的代码。如果你更喜欢用Java代码做这件事情,使用 Butter Knife来避免繁琐的代码。
-
如果你的UI非常复杂,考虑创建一个Presenter类来处理UI的变动。通常这会有点多余,但可能会让UI的测试更加简单。
-
绝对不要在 ViewModel中引用View 或者 Activity 的context。如果ViewModel活的比Activity更长,Activity可能会泄漏,无法正常回收。
附
自定义Activity或者Fragment实现LifecycleOwner
任何自定义的fragment或者activity都可以通过实现LifecycleRegistryOwner 接口变成一个 LifecycleOwner(而不是继承LifecycleFragment 或者 LifecycleActivity)。
public class MyFragment extends Fragment implements LifecycleRegistryOwner {
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}
如果你有一个自定义的类想成为 LifecycleOwner, 你可以使用 LifecycleRegistry 类,但是你需要向那个类传递事件。这个传递在实现了LifecycleRegistryOwner接口的fragment或者activity中是自动完成的。