翻译自https://developer.android.com/topic/libraries/architecture/lifecycle 。
Lifecycle-aware
相关的组件能做出一些操作来响应其他构件1 中的状态变化,比如Activity
或者Fragment
。Lifecycle-aware
相关的组件能够帮助我们获得更好的代码结构,更少的代码,使代码更易维护。
一种常见的方式(构件状态监听的方式)是在Activity
和Fragment
的生命周期方法中实现依赖的操作。但是,这种方式导致不良的代码结构以及错误的增加。通过使用Lifecycle-aware
相关的组件,可以将依赖状态的代码从生命周期的方法中移除。
android.arch.lifecycle
包提供了类和接口,让我们可以构建根据Activity
或Fragment
的当前生命周期状态自动调整其行为的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()
,这使得代码难以维护。
此外,无法保证组件在Activity
或Fragment
停止之前启动。如果我们需要执行长时间运行的操作则尤其如此,例如在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
是一个持有关于构件(比如activity或者fragment)的生命周期状态的信息,并且允许其它的对象观察构件状态的类。
Lifecycle
主要使用两个枚举来跟踪其关联的构件的生命周期状态。
一个类可以通过在方法上添加注解来监听构件的声明周期的状态。然后通过调用Lifecycle
的 addObserver()
方法传递观察者的对象。如下:
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
是一个单一的方法接口,表示该类具有Lifecycle
。它有一个方法getLifecycle()
,其实现类必须实现此方法。如果你正在尝试管理整个应用程序进程的生命周期,请参阅ProcessLifecycleOwner
。
此接口从各个类(如Fragment
和AppCompatActivity
)中抽象出生命周期的所有者,并允许编写与其一起使用的构件。任何自定义的应用的类都可以实现LifecycleOwner
接口。
实现LifecycleObserver
的构件与实现LifecycleOwner
的构件可以无缝协作,因为所有者提供生命周期,观察者可以注册观察。(解耦)。
对于位置跟踪的例子,我们可以让MyLocationListener
类实现LifecycleObserver
并且在activity的onCreate()
的方法中初始化它。这允许MyLocationListener
类自给自足,这意味着响应生命周期状态变化的逻辑在MyLocationListener
而不是activity中声明。各个构件存储自己的逻辑使得Activity
和Fragment
的逻辑更易于管理。
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
的组件。库客户端可以轻松地集成这些组件,而无需在客户端进行手动生命周期的管理。
从support库26.1.0的版本开始,Fragment
和Activity
均实现了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;
}
}
保持UI控制器(Activity和Fragment)尽可能精简,UI控制器不应该获取数据,使用 ViewModel
去获取数据,并且观察LiveData
对象将变更映射到View上。
尽力去写数据驱动的UI,UI控制器的责任是当数据变更时更新View,或者用户操作通知ViewModel
。
把数据逻辑放在ViewModel
类中,ViewModel
应该充当UI控制器和应用程序其余部分之间的连接器。但需要注意,ViewModel
责任不是获取数据(例如从网络获取数据)。相反,ViewModel
应调用适当的构件来获取数据,然后将结果提供给UI控制器。
使用Data Binding来维护视图和UI控制器之间的简洁的接口。这可以使视图更具声明性,并最大限度地减少在Activity
和Fragment
中所需的更新代码。如果使用Java编程语言执行此操作,使用Butter Knife
之类的库来避免样板代码并且具有更好的抽象。
如果UI很复杂,请考虑创建一个 presenter类来处理UI修改。这可能是一项艰巨的任务,但它可以使您的UI组件更容易测试。
避免在ViewModel
中引用View
或Activity
上下文。如果ViewModel
周期大于Activity
周期2(在配置更改的情况下),Activity
将泄漏并且垃圾收集器不能回收此Activity
。
Lifecycle-aware
组件在各种情况下都可以更轻松地管理生命周期。比如:
Lifecycle-aware
组件在您的位置应用程序可见时启用细粒度位置更新,并在应用程序位于后台时切换到粗粒度更新。LiveData
一个Lifecycle-aware
组件,应用在用户位置变更时自动更新UI。Lifecycle-aware
组件尽可能地启动视频缓冲,但推迟播放直到应用程序完全启动。还可以使用Lifecycle-aware
组件在销毁应用程序时终止缓冲。Lifecycle-aware
组件在应用程序处于前台时启用网络数据的实时更新(流式传输),并在应用程序进入后台时自动暂停。Lifecycle-aware
组件动画可绘制的内容,并在应用程序位于前台后恢复可绘制的内容。当Lifecycle
属于AppCompatActivity
或Fragment
时3,在调用AppCompatActivity
或Fragment
的onSaveInstanceState()
时,Lifecycle
的状态将更改为CREATED
,并且会派发ON_STOP
事件。(为什么要这么做,下面给出了解释。)
通过onSaveInstanceState()
保存Fragment
或AppCompatActivity
的状态时,在调用ON_START
事件之前,UI认为是不可变的。保存状态后尝试修改UI可能会导致应用程序的导航状态不一致。这就是为什么应用程序在保存状态后运行FragmentTransaction
,则FragmentManager
会抛出异常的原因。
如果观察者关联Lifecycle
不是处于 STARTED
或者之后的状态,LiveData
会通过禁止调用其观察者来防止这种边缘情况。此情况时,在决定调用其观察者之前可以调用isAtLeast()
方法。
不幸的是,在onSaveInstanceState()
之后才会调用AppCompatActivity
的onStop()
方法,在不允许UI状态更改(onSaveInstanceState()
之后)但是Lifecycle
尚未移到CREATED
状态(AppCompatActivity
的onStop()
方法尚未调用)的存在间隙。
为了防止这个问题,版本beta2及其更低的版本中,Lifecycle
类将状态标记为CREATED
,但没有派发事件,因此即使在系统调用onStop()
之前未派发事件,任何检查当前状态的代码都会获得实际值。
不幸的是,这个解决方案有两个主要问题 :
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例子中看到时如何使用它们的。
我们通常说的组件为库,这里翻译成构件是指某个类,与组件不同。 ↩︎
长周期的对象持有短周期的对象,会导致短周期的对象泄露。 ↩︎
AppCompatActivity和Fragment属于support库中的类。 ↩︎