英文源址 Android架构组件之lifecyle
Lifecycle-aware(生命周期感知型)组件能够响应其他组件的生命周期变化,例如activitiy和fragment.这样的组件能够让你更好的组织代码,而且他们显得更轻量,更容易维护.
一个常见的场景就是,我们需要在activitiy或是fragment中在生命周期方法中实现相关的组件方法.总的来说,这种情况导致了代码在组织上比较差,而且会导致一些分散的错误.通过使用生命周期感知型组件,你可以将这些在生命周期方法中实现的代码移除,在组件内部实现即可(更大程度的实现了组件之间的解耦合);
在android.arch.lifecycle
这个包里面,Android 为我们提供了可以让你构建生命周期感知型的组件的 类和相关接口.
备注:
如果想使用android.arch.lifecycle
包里面的功能详见adding components to your project.
Android framework里面的大多数APP组件都是带有生命周期熟悉的.你程序里面的组件生命周期都是被操作系统或是framework(框架层,俗称中间件)来管理的.这些组件对于你的APP运行稳定来说至关重要.不应该对这些组件进行操作,因为可能会导致内存泄露,严重的话还会导致程序崩溃.
想象一下我们有一个显示位置的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()
这样的生命周期中管理多个组件让维护显得很困难.此外,我们在activitiy或是fragment已经是stop前并不能保证组件启动.这种情况很常见,在我们需要一个长时间运行的操作时候,例如在onStart()
方法中进行参数校验工作.如果 onStop()
在 onStart()
之前结束了,这样会导致一个竞争条件(多线程,或者因执行顺序导致数据结果).该情况的出现会让这个组件(myLocationListener)生命周期超出其需要的时间.
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();//myLocationListener 老子又回来啦
}
});
}
@Override
public void onStop() {
super.onStop();
myLocationListener.stop();//老子挂了
}
}
android.arch.lifecycle
包提供了一些类和接口来用比较柔和藕性低的方式帮助你解决这些问题.
Lifecycle
是用来保存组件(例如 activity or a fragment) 生命周期状态的类,该类允许其他对象感知这个状态.
Lifecycle
在每个相关的组件中使用两个枚举类来追踪生命周期状态.
Event(事件)
由framework和 Lifecycle
类分发的生命周期事件.
State(状态)
Lifecycle
类持有的当前组件的状态.
按图思考一下图标上节点之间的状态和事件.
有个类可以通过添加注解的方法监控组件的生命周期状态.你可以为实现Lifecycle
接口的组件调用addObserver()
方法,来讲获得一个observer对象.示例代码如下.
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());
在上述例子中,myLifecycleOwner 对象实现了 LifecycleOwner
接口,我们下面就来说说这个接口.
LifecycleOwner
是一个只含有一个方法的接口,该类表示这个类含有一个Lifecycle
.这个接口有一个叫做getLifecycle()
的方法.如果你想要管理生个APP的生命周期,那么看看ProcessLifecycleOwner
.
这个接口把像Fragment
和AppCompatActivity
这样的类和生命周期之间进行抽象,允许针对这些类(fragment 和activity)书写一些组件.自定义的application都可以实现这个接口.
实现了 LifecycleObserver
接口的组件可以和实现了LifecycleOwner
组件进行无缝连接,因为一个可以提供lifecycle,另一个可以观察lifecycle.
就拿地址追踪为例,我们可以让MyLocationListener实现
LifecycleObserver
然后在onCreate()
方法中使用activity的 Lifecycle
进行初始化. 这样 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();
}
});
}
}
一个常见的案例就是如果生命周期状态不稳定避免调用相关的回调. 例如当回调在activity 状态保存后运行fragment transaction,将导致crash(不了解的同学,复习一下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中使用它,我们只需要对其进行初始化即可.
如果一个library需要处理与生命周期相关的任务,那么我建议使用生命周期感知型组件.你的library能够轻易的管理生命周期,而不需要手工的写很多代码.
在Support Library 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;
}
}
ViewModel
去处理数据,观察一个LiveData
ViewModel
将你的数据逻辑放入ViewModel
ViewModel
应该作为你的UI控制层和其他层的连接器,但是请狐疑获取网络数据不是viewmodel的职责.相反viewmodel 应该让组件去获取数据,然后处理结果返回给UI控制层.
使用Data Binding 来在view和UI控制层直接维护一个简洁的接口.这可以允许你讲view更多的是声明式的,最小化更新代码.如果你想要这么做,可以使用Butter Knife 来获得更好的抽象.
If your UI is complex, consider creating a
presenter
class to handle UI modifications. This might be a laborious task, but it can make your UI components easier to test.
如果你的UI界面相对复杂,考虑创建一个presenter 来处理UI 变化,这么做可能看起来工作量提升不少,不过这个让你的UI组将更容易测试.
在ViewModel
中避免使用view,activity,fragment的,这样可以避免内存泄露.
生命周期感知型的组件可以让管理生命变得更加简单,下面有几个例子:
在高精度和低精度地理位置之间的切换.使用生命周期感知型的组件能够使用高精度获取地理位置在你的APP可见时候,当你的APP切换到后台的时候使用低精度更新.
启动和关闭视频缓冲.使用生命周期感知型组件来打开视频缓冲.你也可以在在app关闭的时候关闭视频缓冲.
启动和关闭网络连接.使用生命周期感知型组件能够允许app在前台时候更新网络数据,在app在后台时候自动暂停.
暂停和重启动画,
当一个lifecyle 属于AppCompatActivity
或者Fragment
时,调用onSaveInstanceState()
,方法, Lifecycle
状态变成 CREATED
,分发ON_STOP
.
当fragment 或者AppCompatActivity
状态在onSaveInstanceState()
保存了,他的界面就会被认为不可以改变,直到 ON_START
事件被调用. 在state被保存后修改UI,会因状态的不连续产生异常.这是为什么在app 状态被保存后运行FragmentTransaction
会报异常.
LiveData
避免了这些边缘性案例的产生,它通过观察相关的LifeCycle 状态是不是STARTED.在这个场景下它在调用observer之前调用了一个isAtLeast()
不幸的是,AppCompatActivity
的onStop( )
方法在onSaveInstanceState()
之后被调用, 这会导致UI状态状态改变的时候留下一个空白期.
为了避免这个问题,Lifecycle
类在beta2 版本和更低的版本 标记状态为 CREATED
,这样任何代码都能检查当前状态,并且获得真是的值,知道onStop被系统调用.
不幸的是这个解决方案有两个主要问题:
在Api 23以下,Android 系统保存状态即便activity被复写了.换句话说,Android系统调用onSaveInstanceState()
但是不必调用onstop.这会产生一个潜在问题,有个时间段observer还认为生命周期处于活跃状态,但是事实UI状态不能被更改了.
任何想要实现LiveData
类 的类似功能都要实现Lifecycle
beta2 或以下的版本.
备注:
为了让整个流程更加简单,提供更好的兼容性,使用1.0.0-rc1 版本
,
Lifecycle
对象会被标记成CREATED
(状态)和ON_STOP
(事件) 如果onSaveInstanceState()
被调用时,而不需要等到onStop()方法.这一般对你的代码不会造成什么影响,不过你还是应该知道在 API 26 及以下顺序和你想象的有些区别.