Android Lifecycle详解(一)

2024-06-19 11:18
文章标签 android 详解 lifecycle

本文主要是介绍Android Lifecycle详解(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

官方文档翻译

  • 使用生命周期感知组件处理生命周期
  • Lifecycle
    • Event
    • State
    • LifecycleOwner
    • 实现一个自定义的LifecycleOwner
  • 生命周期感知组件的最佳实践
  • 生命周期感知组件的使用场景
  • 停止事件处理
  • 附加资源

使用生命周期感知组件处理生命周期

生命周期感知组件响应于另一组件的生命周期状态(如Activity和Fragment)的变化而执行动作。这些组件有助于产生更好的组织性和更轻的重量代码,这更易于维护。

一种常见的模式是在Activity和Fragment的生命周期方法中实现依赖组件的动作。然而,这种模式导致代码的组织和错误扩散。通过使用生命周期感知组件,可以将依赖组件的代码从生命周期方法中移入组件本身。

android.arch.lifecycle包提供了类和接口,这些类和接口允许您构建生命周期感知组件,这些组件可以根据Activity或Fragment的当前生命周期状态自动调整其行为。

Lifecycle的依赖,包括LiveData和 ViewModel。

dependencies {def lifecycle_version = "1.1.1"// ViewModel and LiveDataimplementation "android.arch.lifecycle:extensions:$lifecycle_version"// alternatively - just ViewModelimplementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin// alternatively - just LiveDataimplementation "android.arch.lifecycle:livedata:$lifecycle_version"// alternatively - Lifecycles only (no ViewModel or LiveData).//     Support library depends on this lightweight importimplementation "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 compilerimplementation "android.arch.lifecycle:common-java8:$lifecycle_version"// optional - ReactiveStreams support for LiveDataimplementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"// optional - Test helpers for LiveDatatestImplementation "android.arch.core:core-testing:$lifecycle_version"
}

AndroidX

dependencies {def lifecycle_version = "2.0.0-beta01"// ViewModel and LiveDataimplementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"// alternatively - just ViewModelimplementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // use -ktx for Kotlin// alternatively - just LiveDataimplementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"// alternatively - Lifecycles only (no ViewModel or LiveData). Some UI//     AndroidX libraries use this lightweight import for Lifecycleimplementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin// alternately - if using Java8, use the following instead of lifecycle-compilerimplementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"// optional - ReactiveStreams support for LiveDataimplementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // use -ktx for Kotlin// optional - Test helpers for LiveDatatestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}

在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;@Overridepublic void onCreate(...) {myLocationListener = new MyLocationListener(this, (location) -> {// update UI});}@Overridepublic void onStart() {super.onStart();myLocationListener.start();// manage other components that need to respond// to the activity lifecycle}@Overridepublic 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});}@Overridepublic void onStart() {super.onStart();Util.checkUserStatus(result -> {// what if this callback is invoked AFTER activity is stopped?if (result) {myLocationListener.start();}});}@Overridepublic void onStop() {super.onStop();myLocationListener.stop();}
}

android.arch.lifecycle包提供了类和接口,帮助您以弹性和独立的方式解决这些问题。

Lifecycle

Lifecycle是一个包含组件生命周期状态(如activity或fragment)信息的类,并允许其他对象观察该状态。

Lifecycle主要使用两个枚举来跟踪其相关组件的生命周期状态:

Event

从框架和Lifecycle类中分派的生命周期事件。这些事件映射到activities和fragments中的回调事件。

State

Lifecycle对象跟踪的组件的当前状态。

把状态看作图和事件的节点,作为这些节点之间的边缘。

一个类可以通过向其方法添加注解来监视组件的生命周期状态。然后,您可以通过调用Lifecycle类的addObserver()方法添加一个观察者,并传递观察者的实例,如下面的示例所示:
image

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

LifecycleOwner是一个单一的方法接口,表示该类具Lifecycle。它有一个方法,getLifecycle(),它必须被实现。如果您试图管理整个应用程序的生命周期,请参阅ProcessLifecycleOwner。

该接口从单个类(如Fragment和AppCompatActivity)抽象出Lifecycle的所有权,并允许编写与其共同工作的组件。任何自定义应用程序类都可以实现LifecycleOwner接口。

实现LifecycleObserver的组件与实现LifecycleOwner的组件无缝协作,因为所有者可以提供一个生命周期,观察者可以注册来监视该生命周期。

对于位置跟踪示例,我们可以使MyLocationListener类实现LifecycleObserver,然后在activity的Lifecycle的onCreate()方法中初始化它。这允许MyLocationListener类自给自足,意味着对生命周期状态的变化做出反应的逻辑在MyLocationListener中定义而不是activity。让各个组件存储它们自己的逻辑,使得activities和fragments逻辑更易于管理。

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现在不处于一个合适的状态,常见的做法是避免调用某些回调。例如,如果一个回调函数运行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 一起使用,我们建议您使用生命周期感知组件。您客户端的lib可以轻松地将这些组件集成在客户端上而无需手动管理生命周期。

实现一个自定义的LifecycleOwner

支持库26.1.0中的Fragment和Activities已经实现了LifecycleOwner接口.

如果您有一个自定义类,您想创建一个LifecycleOwner,您可以使用LifecycleRegistry类,但是您需要将事件转发到该类中,如下面的代码示例所示:

public class MyActivity extends Activity implements LifecycleOwner {private LifecycleRegistry mLifecycleRegistry;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mLifecycleRegistry = new LifecycleRegistry(this);mLifecycleRegistry.markState(Lifecycle.State.CREATED);}@Overridepublic void onStart() {super.onStart();mLifecycleRegistry.markState(Lifecycle.State.STARTED);}@NonNull@Overridepublic Lifecycle getLifecycle() {return mLifecycleRegistry;}
}

生命周期感知组件的最佳实践

保持UI控制器(activities和fragments)尽可能轻量级。他们不应该试图获取他们自己的数据;相反,使用ViewModel来做这件事,并观察LiveData对象,以将数据变化返回给视图。

尝试编写数据驱动的UI,其中UI控制器的职责是在数据更改时更新视图,或将用户操作通知回ViewModel。

将你的数据逻辑放在ViewModel类中。ViewModel应充当UI控制器和应用程序其余部分之间的连接器。但是要注意,ViewModel的责任不是用来获取数据(例如,从一个网络获取数据)。相反,ViewModel应该调用适当的组件来获取数据,然后将结果提供给UI控制器。

使用Data Binding来维护View和UI控制器之间的干净接口。这可以让您的视图更具声明性,并最小化您需要在activities和fragments中写入的更新代码。如果你习惯用Java编程语言做这件事,使用像Butter Knife这样的库来避免样板代码并有更好的抽象。

如果UI复杂,请考虑创建一个presenter类来处理UI修改。这可能是一项费力的任务,但它可以使UI组件更容易测试。

避免在ViewModel中引用View或者Activity的上下文。如果ViewModel超出了activity(在配置改变的情况下),那么您的activity就会内存泄漏,并且不能被垃圾收集器正确地处理。

生命周期感知组件的使用场景

  • 生命周期感知组件可以使您在各种情况下更容易管理生命周期。举几个例子:

  • 在粗粒度和细粒度位置更新之间切换。使用生命周期感知的组件,使细粒度的位置更新,而您的位置应用程序是可见的,并切换到粗粒度更新时,应用程序是在后台。LiveData是一个生命周期感知组件,允许你的app自动更新UI,在用户更改位置的时候。

  • 停止和启动视频缓冲。使用生命周期感知的组件尽快启动视频缓冲,但推迟播放直到应用程序完全启动。当应用程序被销毁时,还可以使用生命周期感知组件来终止缓冲。

  • 启动和停止网络连接。当应用程序处于前台,使用生命周期感知的组件来启用网络数据的实时更新(流),并且当应用程序进入后台时也会自动暂停。

  • 停止和恢复动画drawables。当应用程序处于后台时,使用生命周期感知的组件来停止动画,当应用程序处于前台之后恢复动画播放。

停止事件处理

当Lifecycle属于AppCompatActivity或Fragment时,生命周期的状态将更改为CREATED,而当AppCompatActivity或Fragment的onSaveInstanceState()被调用时,ON_STOP事件将被调度。

当通过onSaveInstanceState()保存Fragment或AppCompatActivity的状态时,其UI被认为是不可变的,直到调用ON_START。试图在保存状态后修改UI可能会导致应用程序导航状态的不一致,这是为什么如果在保存状态后应用程序运行FragmentTransaction,则FragmentManager抛出异常。有关详细信息,请参阅commit()。

LiveData阻止了它的边缘情况,通过阻止调用observer,如果observer关联的Lifecycle不是在STARTED状态。在幕后,它调用isAtLeast(),然后决定调用它的observer。

不幸的是,AppCompatActivity的onStop()方法是在onSaveInstanceState()之后调用的,它留下了一个不允许UI状态改变的间隙,但是Lifecycle还没有被移动到创建的状态。

为了防止这种情况,BETA2版本以及更低版本标记这个状态为CREATED,并且没有分发这个事件,以至于任何代码段检查当前的状态来获取真正的值,尽管事件在 onStop()被调用的时候 才会被分发。

不幸的是,这个解决方案有两个主要问题:

  • 在API级别23和更低的情况下,Android系统实际上保存了活动的状态,即使它被另一个activity部分覆盖。换句话说,Android系统调用onSaveInstanceState(),但它不一定调用onStop()。这就形成了一个潜在的长间隔,以至于观察者仍然认为生命周期是活动的,而此时它的UI状态不能被修改。

  • 任何想要向LiveData类暴露类似行为的类都必须实现Lifecycle Beta2版本或者更低版本提供的解决方案。

注意: 为了使流程更简单,并与旧版本提供更好的兼容性,从版本1.0.0 RC1开始,Lifecycle对象被标记为CREATED,当onSaveInstanceState()被调用时, ON_STOP事件被分发,而不需等待调用onStop()方法。这不太可能影响您的代码,但这里你需要注意,因为它与API级别26和更低的Activity类中的调用顺序不匹配。

附加资源

尝试lifecycle 组件 codelab.

生命周期感知组件是Android Jetpack的一部分。在Sunflower演示应用程序中可以看到他们。

这篇关于Android Lifecycle详解(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1074875

相关文章

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

详解Java中的敏感信息处理

《详解Java中的敏感信息处理》平时开发中常常会遇到像用户的手机号、姓名、身份证等敏感信息需要处理,这篇文章主要为大家整理了一些常用的方法,希望对大家有所帮助... 目录前后端传输AES 对称加密RSA 非对称加密混合加密数据库加密MD5 + Salt/SHA + SaltAES 加密平时开发中遇到像用户的

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Springboot使用RabbitMQ实现关闭超时订单(示例详解)

《Springboot使用RabbitMQ实现关闭超时订单(示例详解)》介绍了如何在SpringBoot项目中使用RabbitMQ实现订单的延时处理和超时关闭,通过配置RabbitMQ的交换机、队列和... 目录1.maven中引入rabbitmq的依赖:2.application.yml中进行rabbit

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

SpringBoot使用Apache POI库读取Excel文件的操作详解

《SpringBoot使用ApachePOI库读取Excel文件的操作详解》在日常开发中,我们经常需要处理Excel文件中的数据,无论是从数据库导入数据、处理数据报表,还是批量生成数据,都可能会遇到... 目录项目背景依赖导入读取Excel模板的实现代码实现代码解析ExcelDemoInfoDTO 数据传输

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2