架构库版本:1.0.0 Alpha 2 - June 2, 2017
android.arch.lifecycle
包提供了可以用于构建生命周期感知(lifecycle-aware)组件的类和接口,这些组件可以根据 Activity 或 Fragment 的当前生命周期自动调整其行为。
注:导入
android.arch.lifecycle
到项目中请参看添加组件到项目。
Android Framework 中定义的大多数应用程序组件都附有生命周期。这些生命周期由操作系统或在进程中运行的框架代码管理。它们是 Android 运行的核心并且应用程序必须遵守它们,不这样做可能会导致内存泄漏甚至应用程序崩溃。
假设我们有一个需要在屏幕上显示设备位置的 Activity。常见的实现方式可能如下所示:
class MyLocationListener {
public MyLocationListener(Context context, Callback callback) {
// ...
}
void start() {
// 链接到系统定位服务
}
void stop() {
// 断开系统定位服务
}
}
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, (location) -> {
// 更新 UI
});
}
public void onStart() {
super.onStart();
myLocationListener.start();
}
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
尽管这个例子看起来不错,在真正的应用程序中,你最终会有太多的类似调用并且会导致 onStart() 和 onStop() 方法变的非常臃肿。
另外,一些组件不能在 onStart() 方法中立即启动。如果我们需要在启动位置观察者之前检查一些配置怎么办?在某些情况下很可能发生 Activity 停止后才检查配置完成,这意味着在 myLocationListener.stop() 被调用之后 myLocationListener.start() 才被调用,会导致定位服务基本上永远保持连接。
class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, location -> {
// 更新 UI
});
}
public void onStart() {
super.onStart();
Util.checkUserStatus(result -> {
// 如果这个回调在 Activity 停止后被调用怎么办?
if (result) {
myLocationListener.start();
}
});
}
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
android.arch.lifecycle
包提供了类和接口帮助以弹性和隔离的方式解决这些问题。
Lifecycle
Lifecycle 是一个类,它持有关于组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他对象观察此状态。
Lifecycle 使用两个主要的枚举来跟踪其关联组件的生命周期状态。
Event:生命周期事件是从框架和 Lifecycle 发出的事件。这些事件映射到 Activity 和 Fragment 中的回调事件。
State: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 是一个单一方法的接口,它表示实现类具有一个 Lifecycle。它有一个 getLifecycle()) 方法,该方法必须由实现类实现。
该实现类从个别的类(例如 Activity 和 Fragment)提取生命周期的所有权,并且允许编写可与两者兼容的组件。任何自定义应用程序类都可以实现 LifecycleOwner 接口。
注:由于 Architecture Components 处于 alpha 阶段,所以 Fragment 和 AppCompatActivity 不能实现 LifecycleOwner (因为我们不能在稳定的组件中添加依赖不稳定的API)。在 Lifecycle 稳定之前,为了方便提供了 LifecycleActivity 和 LifecycleFragment 类。在 Lifecycles 项目发布后,支持库中的 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 事务,将会导致崩溃,因此我们永远不会想要调用该回调。
为了简化该用例, 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) {
// 连接
}
}
public void enable() {
enabled = true;
if (lifecycle.getState().isAtLeast(STARTED)) {
// 如果没有连接则进行连接
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// 如果已经连接则断开连接
}
}
通过这种实现,LocationListener 类是完全的生命周期感知(lifecycle-aware);它可以进行自己的初始化或清理操作,而不受其 Activity 的管理。如果需要在其它的 Activity 或其他的 Fragment 中使用 LocationListener,只需要初始化它。所有的安装和卸载操作都由类自己管理。
可以与 Lifecycle 一起使用的类称为生命周期感知(lifecycle-aware) 组件。鼓励有需要使用 Android 生命周期的类的库提供生命周期感知(lifecycle-aware) 组件,以便于用户可以轻松的在客户端集成这些类,而不需要手动管理生命周期。
LiveData 是一个生命周期感知(lifecycle-aware) 组件的示例。与 ViewModel 一起使用 LiveData 可以在遵守 Android 生命周期的前提下,更容易地使用数据填充UI。
Lifecycles 的最佳实践
保持 UI 控制器(Activity 和 Fragment)尽可能的精简。它们不应该试图去获取它们所需的数据;相反,要用 ViewModel 来获取,并且观察 LiveData 将数据变化反映到视图中。
尝试编写数据驱动(data-driven)的 UI,即 UI 控制器的责任是在数据改变时更新视图或者将用户的操作通知给 ViewModel。
将数据逻辑放到 ViewModel 类中。ViewModel 应该作为 UI 控制器和应用程序其它部分的连接服务。注意:不是由 ViewModel 负责获取数据(例如:从网络获取)。相反,ViewModel 调用相应的组件获取数据,然后将数据获取结果提供给 UI 控制器。
使用 Data Binding 来保持视图和 UI 控制器之间的接口干净。这样可以让视图更具声明性,并且尽可能减少在 Activity 和 Fragment 中编写更新代码。如果你喜欢在 Java 中执行该操作,请使用像 Butter Knife 这样的库来避免使用样板代码并进行更好的抽象化。
如果 UI 很复杂,可以考虑创建一个 Presenter 类来处理 UI 的修改。虽然通常这样做不是必要的,但可能会让 UI 更容易测试。
不要在 ViewModel 中引用 View 或者 Activity 的 context。因为如果 ViewModel 存活的比 Activity 时间长(在配置更改的情况下),Activity 将会被泄漏并且无法被正确的回收。
附录
在自定义 Activity 和 Fragment 中实现 LifecycleOwner
任何自定义的 Fragment 或 Activity 都可以通过实现内置的 LifecycleRegistryOwner 接口转换为 LifecycleOwner(而不是继承 LifecycleActivity 或 LifecycleFragment)
public class MyFragment extends Fragment implements LifecycleRegistryOwner {
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}
如果要创建一个 LifecycleOwner 的自定义类,可以使用 LifecycleRegistry 类,但是需要将事件转发到该自定义类中。如果是 Fragment 和 Activity 实现了 LifecycleRegistryOwner 接口,则此转发会自动完成。