Android 架构组件之 LifeCycle详解
使用生命周期感知型组件处理生命周期
生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。这些组件有助于您写出更有条理且往往更精简的代码,这样的代码更易于维护。
一种常见的模式是在 Activity 和 Fragment 的生命周期方法中实现依赖组件的操作。但是,这种模式会导致代码条理性很差而且会扩散错误。通过使用生命周期感知型组件,您可以将依赖组件的代码从生命周期方法移入组件本身中。
androidx.lifecycle 软件包提供了可用于构建生命周期感知型组件的类和接口 - 这些组件可以根据 Activity 或 Fragment 的当前生命周期状态自动调整其行为。
internal class MyLocationListener(
private val context: Context,
private val callback: (Location) -> Unit
) {
fun start() {
// connect to system location service
}
fun stop() {
// disconnect from system location service
}
}
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
myLocationListener.start()
// manage other components that need to respond
// to the activity lifecycle
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
// manage other components that need to respond
// to the activity lifecycle
}
}
虽然此示例看起来没问题,但在真实的应用中,最终会有太多管理界面和其他组件的调用,以响应生命周期的当前状态。管理多个组件会在生命周期方法(如 onStart() 和 onStop())中放置大量的代码,这使得它们难以维护。
此外,无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 onStart() 中的某种配置检查)时尤其如此。这可能会导致出现一种竞争条件,在这种条件下,onStop() 方法会在 onStart() 之前结束,这使得组件留存的时间比所需的时间要长。
类和接口
- Lifecycle
Lifecycle是一个持有组件生命周期状态(如Activity或Fragment)的信息的类,并允许其他对象观察此状态。 - Event :从框架和Lifecycle类派发的生命周期事件。这些事件映射到活动和片段中的回调事件。
- State :由Lifecycle对象跟踪的组件的当前状态。
您可以将状态看作图中的节点,将事件看作这些节点之间的边。
类可以通过向其方法添加注解来监控组件的生命周期状态。然后,您可以通过调用 Lifecycle 类的 addObserver() 方法并传递观察者的实例来添加观察者,
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
...
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener() {
...
}
}
myLifecycleOwner.getLifecycle().addObserver(MyObserver())
- LifecycleOwner (重要)Lifecycle持有者
- LifecycleOwner 是单一方法接口,表示类具有 Lifecycle。它具有一种方法(即 getLifecycle()),该方法必须由类实现。如果您尝试管理整个应用进程的生命周期,使用 ProcessLifecycleOwner。
- 此接口从各个类(如 Fragment 和 AppCompatActivity)抽象化 Lifecycle 的所有权,并允许编写与这些类搭配使用的组件。任何自定义应用类均可实现 LifecycleOwner 接口。
- 实现 LifecycleObserver 的组件可与实现 LifecycleOwner 的组件无缝协同工作,因为所有者可以提供生命周期,而观察者可以注册以观察生命周期。
- 对于位置跟踪示例,我们可以让 MyLocationListener 类实现 LifecycleObserver,然后在 onCreate() 方法中使用 Activity 的 Lifecycle 对其进行初始化。这样,MyLocationListener 类便可以“自给自足”,这意味着,对生命周期状态的变化做出响应的逻辑会在 MyLocationListener(而不是在 Activity)中进行声明。让各个组件存储自己的逻辑,可使 Activity 和 Fragment 逻辑更易于管理
-
class MyActivity : AppCompatActivity() { private lateinit var myLocationListener: MyLocationListener override fun onCreate(...) { myLocationListener = MyLocationListener(this, lifecycle) { location -> // update UI } Util.checkUserStatus { result -> if (result) { myLocationListener.enable() } } } }
一个常见的用例是,如果 Lifecycle 现在未处于良好的状态,则应避免调用某些回调。例如,如果回调在 Activity 状态保存后运行 Fragment 事务,就会引发崩溃,因此我们绝不能调用该回调。
为简化此用例,Lifecycle 类允许其他对象查询当前状态。
internal class MyLocationListener(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
) {
private var enabled = false
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun start() {
if (enabled) {
// connect
}
}
fun enable() {
enabled = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// connect if not connected
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stop() {
// disconnect if connected
}
}
实现自定义 LifecycleOwner
Support Library 26.1.0 及更高版本中的 Fragment 和 Activity 已实现 LifecycleOwner 接口。官方说已经实现了接口,但是我没看到啊。
如果您有一个自定义类并希望使其成为 LifecycleOwner,您可以使用 LifecycleRegistry 类,但需要将事件转发到该类,如以下代码示例中所示
class MyActivity : Activity(), LifecycleOwner {
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
public override fun onStart() {
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
}
- LifecycleObserver(生命周期观察者接口)
LifecycleObserver 是一个观察者接口,实现了它,可以通过注解或者继承的方式,来管理声明周期的监听。只要在持有lifecycle的类中注册了它,当声明周期发生变化时,它就能收到,进行我们自定义的操作。
两种实现方式:
- 实现DefultLifecyceObserver接口,然后重写里面生命周期方法;
- 直接实现LifecycleObserver接口,然后通过注解的方式来接收生命周期的变化;
Lifecycle.java文档中是建议使用第一种方式,因为文档中说明了,随着Java8成为主流,注解的方式会被弃用。DefaultLifecycleObserver是需要另外声明的java8 比如下面
GenericLifecycleObserver,FullLifecycleObserver,DefaultLifecycleObserver 这三个接口都是直接或者间接继承的LifecycleObserver
Lifecycle的使用
两个简单的Activity,FirstActivity 和SecondActivity, 单纯的一个跳转
public class FirstActivity extends AppCompatActivity {
private Button firstBtn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_activity_layout);
initView();
initListener();
}
private void initView() {
firstBtn = findViewById(R.id.first_btn);
}
private void initListener() {
firstBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
们要做的是要写一个需要拥有声明周期的类,正常我们自定义控件啊,或者做其他逻辑的类,是没有声明周期的,现在有了LifecycleObserver,我们可以让一个普通的类拥有感知声明周期变化的能力。比如,现在自定义一个,MyObserver类。
public class MyObserver implements DefaultLifecycleObserver{
private static final String TAG = "MyListener";
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onCreate()");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onStart()");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
@Override
public void onResume(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onResume()");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onPause()");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onStop()");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
Log.d(TAG,"onDestroy() ");
Log.d(TAG,"当前生命周期状态="+lifecycle.getCurrentState().name());
}
}
直接继承DefaultLifecycleObserver接口,来实现它所有的方法。我们在里面做了log,来查看,是否这个类,收到了activity声明周期的变化。
然后,要做的就是注册监听
在Activity 的OnCreate方法中,调用getLifecycle();
public class FirstActivity extends AppCompatActivity {
private Button firstBtn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_activity_layout);
initView();
initListener();
//添加了这一行代码
getLifecycle().addObserver(new MyObserver());
}
private void initView() {
firstBtn = findViewById(R.id.first_btn);
}
private void initListener() {
firstBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
Activity中可以直接 getLifecycle().addObserver(new MyObserver()); 这样,就已经注册了声明周期观察者的监听。运行查看log
启动FirstActivity后,MyObserver类已经监听到了Activity的声明周期方法
要注意的是:
生命周期状态为RESUMED时表示,当前activity 是在前台,并且可交互也就是onResume()执行后
生命周期状态为STARTED时,表示当前activity处于可见但是不可交互,也就是onStart()方法刚执行完或者onPause()方法刚执行完的状态
生命周期状态为CREATED,表示onCreate()方法刚刚执行完或者onStop()方法刚刚执行完,也就是当前activity不在前台,但是也没有处于销毁状态。
生命周期状态为DESTORYED,表示当前Activity还不存在,没有被创建或者已经销毁,我们通常考虑比较多的就是,onDestory()方法执行后,当前Activity已经销毁。
所以,如果我们要保证在Activity或者Fragment的有效生命周期内进行的操作,必须判断,当前lifecycle的状态是否至少是CREATED状态,避免Activity或者fragment销毁了以后,回调或者网络请求才回来,此时做一些操作会导致异常。
添加以下代码,就是我们把lifecycle对象传给观察者,让它自己去判断回调后的代码,保证至少是CREATED状态
private Lifecycle lifecycle;
public MyObserver(Lifecycle lifecycle) {
this.lifecycle = lifecycle;
}
//然后再相应的回调方法中使用下面代码判断,保证数据回调回来,当前activity是存在的
if (lifecycle.getCurrentState().isAtLeast(CREATED)) {
//这里只是示例,不一定是CREATED
}
生命周期感知型组件的最佳做法
- 尽可能保持您的UI控制器(活动和片段)尽可能精简。他们不应该试图获取他们自己的数据;相反,使用ViewModel来做到这一点,并观察一个LiveData对象来反映更改回视图。
- 尝试编写数据驱动的用户界面,其中您的用户界面控制器的职责是在数据更改时更新视图,或将用户操作通知给ViewModel。
- 把你的数据逻辑放在ViewModel类中。ViewModel应作为您的UI控制器和其他应用程序之间的连接器。但要小心,ViewModel不负责提取数据(例如,来自网络)。相反,ViewModel应调用相应的组件来获取数据,然后将结果提供给UI控制器。
- 使用dataBinding在视图和UI控制器之间保持干净的界面。这使您可以使您的视图更具说明性,并最大限度地减少需要在活动和片段中编写的更新代码。
本文地址:https://blog.csdn.net/lin_henry/article/details/108150227
上一篇: keras 解决加载lstm+crf模型出错的问题
下一篇: C++之文件操作初识
推荐阅读
-
Android动画之逐帧动画(Frame Animation)实例详解
-
Android动画之补间动画(Tween Animation)实例详解
-
Android动画之渐变动画(Tween Animation)详解 (渐变、缩放、位移、旋转)
-
android开发之listView组件用法实例简析
-
详解SpringCloud微服务架构之Hystrix断路器
-
Android编程四大组件之BroadcastReceiver(广播接收者)用法实例
-
Android编程四大组件之Activity用法实例分析
-
Android四大组件之Service(服务)实例详解
-
Android编程中的四大基本组件与生命周期详解
-
Android学习笔记之ListView复用机制详解