使用Lifecycle处理生命周期

泡在网上的日子 / 文 发表于2017-05-24 02:52 次阅读 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中是自动完成的。

收藏 赞 (1) 踩 (2)
上一篇:在项目中添加添加Architecture Components
在开始之前,我们推荐你先阅读关于Architecture Components的文章: App开发架构指南 。这篇指南涵盖了一些可以应用到所有Android app中的有益准则,并演示和如何使用这些Architecture Components。 注:Architecture Components 仍处于alpha版本。在1.0 之
下一篇:Room Persistence Library(官网文档翻译)
Room提供了一个 SQLite之上的抽象层,使得在充分利用 SQLite功能的前提下流畅的访问数据库。 Room 对于需要处理大量结构化数据的App来说,把这些数据做本地持久化会带来很大的好处。常见的用例是缓存重要数据块。这样当设备无法连网的时候,用户仍然可以浏览