本文是对lifecycles原文的学习和翻译。也会加入一些自己的体会。如果你有足够的耐心,就会发现其实没接触之前再难的东西,当你花足够的时间去了解它,你会发现没有什么能难倒你 。附上原文地址:Handling lifecycles with lifecycle-aware components | Android Developers
使用生命周期感知组件来处理生命周期
根据文章标题来看,我们对android各大组件的生命周期都不陌生,但是这里有一个新的概念——生命周期感知组件。这里说白了,就是有这样一个组件如果实现了android.arch.lifecycle提供的接口就能感知如activity/fragment这样的组件的生命周期,当在开发中某个类要依赖生命周期操作就可以这样处理。
感知生命周期的组件可以执行某个动作,以响应其他组件(activity/fragmrnt)的生命周期状态的变化。这些组件有助于产生更好的组织性和更轻量的代码,也更易于维护。
现在的开发中,有一种常见的业务需求。比如某一个业务逻辑,要在activity/fragment的某个生命周期中来完成,这样的方式很容易导致代码的错误扩大化以及影响代码可读性。通过使用生命周期感知组件,可以将依赖组件生命周期的代码从生命周期方法中移出来,这样就减少了某些风险,增加代码可读性。
android.arch.lifecycle提供的类和接口可以让你构建能感知生命周期(lifecycle-aware)的类。所谓可以感知生命周期就是能够感知Activity或者Fragment的生命周期并且可以自行调整类的行为。
那么在我们工程中怎样来依赖呢,根据自己的需要可以选择你想用的库。
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version"
// use -ktx for Kotlin
// alternatively - just LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
// use kapt for Kotlin
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"
// optional - Test helpers for LiveData
testImplementation "android.arch.core:core-testing:$lifecycle_version"
}
这样看起来比较麻烦吧,如果你仅仅是需要 Lifecycle,LiveData ,ViewModel只需要这样进行依赖。
dependencies {
def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
}
当然这么强大的库,肯定是支持kotlin的,kotlin的引用只需要在版本号之前加上-ktx,如下:
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
在Android框架中定义的大多数应用程序组件都有生命周期。生命周期是由操作系统或运行在你的进程中的框架代为管理的。它们是Android工作的核心,你的应用程序必须遵循它们。不这样做可能触发内存泄漏或甚至应用崩溃。
假如现在我们有一个需求,需要在屏幕上显示你的位置。一个常见的实现方式可能如下:
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
}
}
尽管这个示例看起来不错,但是在真正的应用程序中,你最终会在activity的生命周期中有太多的调用,这些调用管理着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 -> {
// 如果activity结束了,这个方法才被调用,怎么办?
if (result) {
myLocationListener.start();
}
});
}
@Override
public void onStop() {
super.onStop();
myLocationListener.stop();
}
}
生命周期包android.arch.lifecycle
提供类和接口,帮助你以更弹性更独离的方式解决这些问题。
Lifecycle
Lifecycle
是一个保存了关于组件(如activity或fragment)的生命周期状态信息的类,并允许其他对象观察该状态。
Lifecycle使用两个主要枚举来跟踪其相关组件的生命周期状态:
Event
从Lifecycle这个框架和Lifecycle类中分发的生命周期事件。这些事件映射到activity和fragment中的对应生命周期事件中。也就是当activity的生命周期被Lifecycle观察,Lifecycle中对应的生命周期能通过映射拿到activity当前的状态。
State
由Lifecycle对象跟踪的组件(activity / fragment)的当前生命周期状态。也就是我们能通过Lifecycle拿到activity/fragment当前的生命周期。
当然这张图我们不用关心,因为看起来不直观啊。我们来直接看看源码中是什么样子。
public enum Event {
/**
* Constant for onCreate event of the {@link LifecycleOwner}.
*/
ON_CREATE,
/**
* Constant for onStart event of the {@link LifecycleOwner}.
*/
ON_START,
/**
* Constant for onResume event of the {@link LifecycleOwner}.
*/
ON_RESUME,
/**
* Constant for onPause event of the {@link LifecycleOwner}.
*/
ON_PAUSE,
/**
* Constant for onStop event of the {@link LifecycleOwner}.
*/
ON_STOP,
/**
* Constant for onDestroy event of the {@link LifecycleOwner}.
*/
ON_DESTROY,
/**
* An {@link Event Event} constant that can be used to match all events.
*/
ON_ANY
}
/**
* Lifecycle states. You can consider the states as the nodes in a graph and
* {@link Event}s as the edges between these nodes.
*/
@SuppressWarnings("WeakerAccess")
public enum State {
/**
* Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
* any more events. For instance, for an {@link android.app.Activity}, this state is reached
* <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
*/
DESTROYED,
/**
* Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
* the state when it is constructed but has not received
* {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
*/
INITIALIZED,
/**
* Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
* <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
* </ul>
*/
CREATED,
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
STARTED,
/**
* Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached after {@link android.app.Activity#onResume() onResume} is called.
*/
RESUMED;
/**
* Compares if this State is greater or equal to the given {@code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given {@code state}
*/
那我们就来看看具体的使用:
一个类可以通过向其方法添加注释来监视组件的生命周期状态。然后通过调用Lifecycle类的addObserver()方法添加观察者,如下面的示例所示:
//通过实现LifecycleObserver,我们就能在自己的类中观察其他组件的生命周期
public class StudyLifecycle implements LifecycleObserver{
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate(){
Logg.i("onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart(){
Logg.i("onStart");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume(){
Logg.i("onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause(){
Logg.i("onPause");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop(){
Logg.i("onStop");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy(){
Logg.i("onDestroy");
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//在这里添加我们的观察者
getLifecycle().addObserver(new StudyLifecycle());
}
}
通过这个例子可以发现,实际上我们拥有生命周期的组件(activity等)实际上是被作为了被观察者,而Lifecycle作为了观察者。这样通过push的方式,我们就能轻松的了解到组件的周期变化。
LifecycleOwner
LifecycleOwner是有单一方法的接口,实现它表示该类具有生命周期。它有一个方法,getLifecycle(),而且是必须由实现的。
这个接口从单独的类(如fragment和AppCompatActivity)抽象出生命周期的所有权,并允许编写与之一起工作的组件。任何自定义应用程序类都可以实现LifecycleOwner接口。
实现LifecycleObserver的组件与实现LifecycleOwner的组件无缝地工作。这样你就能看出来实际上我们这这里用的就是观察者模式,实现了LifecycleOwner接口的类作为被观察者,实现了LifecycleObserver接口的类作为观察者。
对于位置跟踪示例,我们可以使MyLocationListener类实现LifecycleObserver,然后在onCreate()方法中使用activity的Lifecycle初始化它。这允许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();
}
});
}
}
这里有一个问题就是,例如当前的activity在onSaveInstanceState方法执行之后在调用其它回调,则会触发崩溃,因此我们永远不会希望调用该回调。
为了使用变得简单,生命周期类允许其他对象查询当前状态。
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
}
}
//源码中的解释:
/**
* Compares if this State is greater or equal to the given {@code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given {@code state}
*/
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
通过这个实现,我们的LocationListener类完全是能感知生命周期的。如果我们需要从另一个activity或fragment中使用我们的LocationListener,我们只需要初始化它。所有的设置和销毁等操作都是由类本身管理的。
实现自定义的 LifecycleOwner
这里要说的是,activity/fragment在Support Library 26.1.0以及以后的版本已经实现了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;
}
}
当你去查看activity源码时你会发现,源码也是基于这样实现的。并没有什么变化。
生命周期感知组件的最佳实践
- 保持UI控制器(activity/fragment)尽可能简单。它们不应该去直接获取数据;相反,使用ViewModel
来获取数据,并观察LiveData
对象以将数据的变化及时反应到UI。 - 尝试编写数据驱动的UI,其中UI控制器的职责是在数据更改时更新UI,或者将用户操作通知到ViewModel。
- 将数据的逻辑放在View模型类中。View模型应充当UI控制器和应用程序其余部分之间的连接器。但是要小心,ViewModel的责任不是来获取数据(例如,从一个网络)。相反,ViewModel应该调用适当的组件来获取数据,然后将结果返回到UI控制器。
也就是说ViewModel只关心获取数据,但是不关心怎么获取的。听起来有一点绕口。打个比方,这里有很多管子,连接到一个大缸,我在一旁一直看着大缸里的水,监测水位的变化。这里的我就相当于UI及时的得到数据的变化,那么这个大缸就是ViewModel,它只关心缸里的水本身,至于水是从哪个管子里来的,不关心。那么管子就相当于另一个概念Repository,它只专注于水从哪里来,也就是数据的获取渠道。
网友评论