目录

    • Lifecycle
    • LifecycleOwner
      • 实现自定义LifecycleOwner
    • Lifecycle-aware组件的最佳实践
    • 使用Lifecycle-aware组件的场景
    • 处理stop事件
    • 其他资源

翻译自https://developer.android.com/topic/libraries/architecture/lifecycle 。

Lifecycle-aware相关的组件能做出一些操作来响应其他构件1 中的状态变化,比如Activity或者FragmentLifecycle-aware相关的组件能够帮助我们获得更好的代码结构,更少的代码,使代码更易维护。

一种常见的方式(构件状态监听的方式)是在ActivityFragment的生命周期方法中实现依赖的操作。但是,这种方式导致不良的代码结构以及错误的增加。通过使用Lifecycle-aware相关的组件,可以将依赖状态的代码从生命周期的方法中移除。

android.arch.lifecycle包提供了类和接口,让我们可以构建根据ActivityFragment的当前生命周期状态自动调整其行为的Lifecycle-aware的代码。

Note: 在工程中引入 android.arch.lifecycle ,请看 adding components to your project。

Android框架中定义的大多数应用程序组件都附加了生命周期。生命周期由操作系统或运行在进程中的框架代码管理。它们是Android工作原理的核心,我们的应用程序必须遵守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;    @Override    public void onCreate(...) {        myLocationListener = new MyLocationListener(this, (location) -> {            // update UI        });    }    @Override    public void onStart() {        super.onStart();        myLocationListener.start();        // manage other components that need to respond        // to the activity lifecycle    }    @Override    public void onStop() {        super.onStop();        myLocationListener.stop();        // manage other components that need to respond        // to the activity lifecycle    }}

即使这个例子看起来很好。但在真实的应用程序中,会有太多UI的管理和其他构件响应当前状态的生命周期的调用。管理多个构件会在生命周期方法中放置大量代码,例如onStart()onStop(),这使得代码难以维护。

此外,无法保证组件在ActivityFragment停止之前启动。如果我们需要执行长时间运行的操作则尤其如此,例如在onStart()中的某些配置检查。这种情况会引起onStop()方法(的业务操作)在onStart()(的业务操作)之前完成,使得组件保持活动时间超过其所需的时间从而造成竞争条件。

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

android.arch.lifecycle包提供了类和接口,可帮助我们以扩展性和隔离的方式解决这些问题。

Lifecycle

Lifecycle是一个持有关于构件(比如activity或者fragment)的生命周期状态的信息,并且允许其它的对象观察构件状态的类。

Lifecycle主要使用两个枚举来跟踪其关联的构件的生命周期状态。

  • Event

    此生命周期的事件是通过框架和Lifecycle类来分发的。这些事件与ActivityFragment中的事件回调相对应。

  • State

    Lifecycle对象跟踪的构件的当前的状态。

一个类可以通过在方法上添加注解来监听构件的声明周期的状态。然后通过调用LifecycleaddObserver()方法传递观察者的对象。如下:

public class MyObserver implements LifecycleObserver {    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)    public void connectListener() {        ...    }    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)    public void disconnectListener() {        ...    }}myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

LifecycleOwner

LifecycleOwner 是一个单一的方法接口,表示该类具有Lifecycle。它有一个方法getLifecycle(),其实现类必须实现此方法。如果你正在尝试管理整个应用程序进程的生命周期,请参阅ProcessLifecycleOwner

此接口从各个类(如FragmentAppCompatActivity)中抽象出生命周期的所有者,并允许编写与其一起使用的构件。任何自定义的应用的类都可以实现LifecycleOwner接口。

实现LifecycleObserver的构件与实现LifecycleOwner的构件可以无缝协作,因为所有者提供生命周期,观察者可以注册观察。(解耦)。

对于位置跟踪的例子,我们可以让MyLocationListener类实现LifecycleObserver并且在activity的onCreate()的方法中初始化它。这允许MyLocationListener类自给自足,这意味着响应生命周期状态变化的逻辑在MyLocationListener而不是activity中声明。各个构件存储自己的逻辑使得ActivityFragment的逻辑更易于管理。

class MyActivity extends AppCompatActivity {    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) {           // connect        }    }    public void enable() {        enabled = true;        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {            // connect if not connected        }    }    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)    void stop() {        // disconnect if connected    }}

通过此实现,我们的LocationListener类完全可以识别生命周期。如果我们想要在其他的Activity或者Fragment中使用LocationListener类,仅仅需要初始化就可以了。所有设置和拆卸操作都由类本身管理。

如果库提供了需要使用Android生命周期的类,建议使用生命周期Lifecycle-aware的组件。库客户端可以轻松地集成这些组件,而无需在客户端进行手动生命周期的管理。

实现自定义LifecycleOwner

从support库26.1.0的版本开始,FragmentActivity均实现了LifecycleOwner 接口。

如果有自定义类,想要实现LifecycleOwner,可以使用LifecycleRegistry 类,但是需要在类中跟踪事件,代码如下:

public class MyActivity extends Activity implements LifecycleOwner {    private LifecycleRegistry mLifecycleRegistry;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mLifecycleRegistry = new LifecycleRegistry(this);        mLifecycleRegistry.markState(Lifecycle.State.CREATED);    }    @Override    public void onStart() {        super.onStart();        mLifecycleRegistry.markState(Lifecycle.State.STARTED);    }    @NonNull    @Override    public Lifecycle getLifecycle() {        return mLifecycleRegistry;    }}

Lifecycle-aware组件的最佳实践

  • 保持UI控制器(Activity和Fragment)尽可能精简,UI控制器不应该获取数据,使用 ViewModel去获取数据,并且观察LiveData对象将变更映射到View上。

  • 尽力去写数据驱动的UI,UI控制器的责任是当数据变更时更新View,或者用户操作通知ViewModel

  • 把数据逻辑放在ViewModel类中,ViewModel应该充当UI控制器和应用程序其余部分之间的连接器。但需要注意,ViewModel责任不是获取数据(例如从网络获取数据)。相反,ViewModel应调用适当的构件来获取数据,然后将结果提供给UI控制器。

  • 使用Data Binding来维护视图和UI控制器之间的简洁的接口。这可以使视图更具声明性,并最大限度地减少在ActivityFragment中所需的更新代码。如果使用Java编程语言执行此操作,使用Butter Knife之类的库来避免样板代码并且具有更好的抽象。

  • 如果UI很复杂,请考虑创建一个 presenter类来处理UI修改。这可能是一项艰巨的任务,但它可以使您的UI组件更容易测试。

  • 避免在ViewModel中引用ViewActivity上下文。如果ViewModel周期大于Activity周期2(在配置更改的情况下),Activity将泄漏并且垃圾收集器不能回收此Activity

使用Lifecycle-aware组件的场景

Lifecycle-aware组件在各种情况下都可以更轻松地管理生命周期。比如:

  • 在粗粒度和细粒度位置更新之间切换。使用Lifecycle-aware组件在您的位置应用程序可见时启用细粒度位置更新,并在应用程序位于后台时切换到粗粒度更新。LiveData一个Lifecycle-aware组件,应用在用户位置变更时自动更新UI。
  • 停止和开始视频缓冲,使用Lifecycle-aware组件尽可能地启动视频缓冲,但推迟播放直到应用程序完全启动。还可以使用Lifecycle-aware组件在销毁应用程序时终止缓冲。
  • 启动和停止网络连接。使用Lifecycle-aware组件在应用程序处于前台时启用网络数据的实时更新(流式传输),并在应用程序进入后台时自动暂停。
  • 暂停和恢复动画drawables。当应用程序在后台时,使用Lifecycle-aware组件动画可绘制的内容,并在应用程序位于前台后恢复可绘制的内容。

处理stop事件

Lifecycle属于AppCompatActivityFragment3,在调用AppCompatActivityFragmentonSaveInstanceState()时,Lifecycle的状态将更改为CREATED,并且会派发ON_STOP事件。(为什么要这么做,下面给出了解释。)

通过onSaveInstanceState()保存FragmentAppCompatActivity的状态时,在调用ON_START事件之前,UI认为是不可变的。保存状态后尝试修改UI可能会导致应用程序的导航状态不一致。这就是为什么应用程序在保存状态后运行FragmentTransaction,则FragmentManager会抛出异常的原因。

如果观察者关联Lifecycle 不是处于 STARTED或者之后的状态,LiveData会通过禁止调用其观察者来防止这种边缘情况。此情况时,在决定调用其观察者之前可以调用isAtLeast()方法。

不幸的是,在onSaveInstanceState()之后才会调用AppCompatActivityonStop()方法,在不允许UI状态更改(onSaveInstanceState()之后)但是Lifecycle 尚未移到CREATED状态(AppCompatActivityonStop()方法尚未调用)的存在间隙。

为了防止这个问题,版本beta2及其更低的版本中,Lifecycle 类将状态标记为CREATED,但没有派发事件,因此即使在系统调用onStop()之前未派发事件,任何检查当前状态的代码都会获得实际值。

不幸的是,这个解决方案有两个主要问题 :

  • 在API23及更低版本,Android系统实际上保存了活动的状态(调用了onSaveInstanceState()),即使它被另一个Activity部分覆盖。换句话说,Android系统调用onSaveInstanceState但它不一定调用onStop()。这会创建一个潜在的长间隔,即使无法修改其UI状态,但观察者仍然认为生命周期处于活跃状态。
  • 任何想要向LiveData暴露类似行为的类,都必须提供Lifecycle 版本 beta 2及更低版本提供的解决方法。

Notice : 为了简化流程并提供与旧版本的更好兼容性,从版本1.0.0-rc1开始,当onSaveInstanceState()调用时,不会等待onStop()的调用,Lifecycle对象标记为CREATED,并且通知ON_STOP。这不太可能影响代码,但需要注意这一点,它与API26及更低版本的Activity类中的调用顺序不匹配。

其他资源

尝试使用Lifecycle组件请看codelab。

Lifecyle-aware组件是Android Jetpack的一部分,可以在Sunflower例子中看到时如何使用它们的。


  1. 我们通常说的组件为库,这里翻译成构件是指某个类,与组件不同。 ↩︎

  2. 长周期的对象持有短周期的对象,会导致短周期的对象泄露。 ↩︎

  3. AppCompatActivity和Fragment属于support库中的类。 ↩︎

更多相关文章

  1. Android(安卓)GPS定位详解
  2. Android改变状态栏颜色真麻烦
  3. Android(安卓)关于判断应用是否有网络
  4. android activty的生命周期
  5. Android7.0 禁止锁屏状态的下拉状态栏
  6. Android(安卓)View 绘制流程之四:绘制流程触发机制
  7. Android(安卓)permission列表
  8. [AndroidTips]Android软件测试的日志文件抓取简介
  9. Android(安卓)TelephonyManager类的使用

随机推荐

  1. Android Framework学习——view的创建(1)
  2. Android源码分析:HeaderViewListAdapter
  3. 万树:Java和Android有什么联系?有什么区别
  4. Android动态加载之ClassLoader —热修复
  5. Android面试心得和应对思路
  6. Android加密与iOS加密技术分析
  7. Android ActionBar的源代码分析(三)
  8. Android 2.3 Dev Guide (55)-- Android S
  9. Android 开发未来的出路何在? | 技术头条
  10. Android(安卓)四种加载方式详解(standard