架构库版本: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 接口,则此转发会自动完成。

更多相关文章

  1. android拾遗——四大基本组件介绍与生命周期
  2. 自定义MediaPlayer控制组件
  3. Android获取屏幕高度、状态栏高度、标题栏高度
  4. Android桌面组件开发例子
  5. coordinatelayout android:fitsSystemWindows 沉浸式状态栏在and
  6. Android(安卓)中Service组件
  7. selector 背景选择器
  8. 【Android(安卓)Developers Training】 14. 序言:管理Activity生
  9. Android(安卓)Fragment 真正的完全解析(上)

随机推荐

  1. HTML表单内容的详细介绍
  2. html练习之表单标签使用
  3. 学习基本元素布局视窗
  4. 怎么给网站建立一级目录
  5. 如何优化网站权重页?
  6. 长尾关键词有那几种形式?
  7. 域名对SEO优化到底有多大影响!
  8. 影响搜索排名的用户行为
  9. 安装vscode,学习emmet语法
  10. 11个SEO最常见问题解答