【Android Jetpack】Lifecycle 感知生命周期

文章目录

    • 背景
    • 示例
    • LifeCycle的原理
      • LifecycleOwner
      • 自定义LifecycleOwner
      • LifecycleObserver
    • 示例改进
    • 使用LifecycleService解耦Service与组件
    • 整个应用进程的生命周期ProcessLifecycleOwner

背景

在Android应用程序开发中,解耦很大程度上表现为系统组件的生命周期与普通组件之间的解耦。普通组件在使用过程中通常需要依赖于系统组件的生命周期。有时候,我们不得不在系统组件的生命周期回调方法中,主动对普通组件进行调用或控制。因为普通组件无法主动获知系统组件的生命周期事件。

我们希望我们对自定义组件的管理,不依赖于页面生命周期的回调方法。同时,在页面生命周期发生变化时,也能够及时收到通知。这在组件化和架构设计中显得尤为重要。

为此,Google提供了LifeCycle作为解决方案。LifeCycle可以帮助开发者创建可感知生命周期的组件。这样,组件便能够在其内部管理自己的生命周期,从而降低模块间的耦合度,并降低内存泄漏发生的可能性。LifeCycle不只对Activity/Fragment有用,在Service和Application中也能大显身手。

示例

Android开发中,经常需要管理生命周期。举个栗子,我们需要获取用户的地址位置,当这个Activity在显示的时候,我们开启定位功能,然后实时获取到定位信息,当页面被销毁的时候,需要关闭定位功能。

internal class MyLocationListener(private val context: Context,private val callback: (Location) -> Unit
) {fun start() {// 连接系统定位服务以及其他业务}fun stop() {//断开系统定位服务}
}class MyActivity : AppCompatActivity() {private lateinit var myLocationListener: MyLocationListeneroverride fun onCreate(...) {myLocationListener = MyLocationListener(this) { location ->...}}public override fun onStart() {super.onStart()myLocationListener.start()}public override fun onStop() {super.onStop()myLocationListener.stop()}
}

虽然此示例看起来没问题,但在真实的应用中,最终会有太多管理界面和其他组件的调用,以响应生命周期的当前状态。管理多个组件会在生命周期方法(如 onStart()onStop())中放置大量的代码,这使得它们难以维护。

此外,无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 onStart() 中的某种配置检查)时尤其如此。这可能会导致出现一种竞态条件,在这种条件下,onStop() 方法会在 onStart() 之前结束,这使得组件留存的时间比所需的时间要长。

class MyActivity : AppCompatActivity() {private lateinit var myLocationListener: MyLocationListeneroverride fun onCreate(...) {myLocationListener = MyLocationListener(this) { location ->// update UI}}public override fun onStart() {super.onStart()Util.checkUserStatus { result ->// what if this callback is invoked AFTER activity is stopped?if (result) {myLocationListener.start()}}}public override fun onStop() {super.onStop()myLocationListener.stop()}}

Lifecycle类是一个持有组件(activityfragment)生命周期信息的类,其他对象可以观察该状态。Lifecycle使用两个重要的枚举部分来管理对应组件的生命周期的状态:

  • Event:生命周期事件,由系统来分发,这些事件对应于ActivityFragment的生命周期函数。

  • State:Lifecycle对象所追踪的组件的当前状态

image-20230921165716822

LifeCycle的原理

Jetpack为我们提供了两个类:

  • LifecycleOwner: 被观察者
  • LifecycleObserver: 观察者

通过观察者模式,实现对页面生命周期的监听。

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
}            
public class FragmentActivity extends ComponentActivity implementsActivityCompat.OnRequestPermissionsResultCallback,ActivityCompat.RequestPermissionsRequestCodeValidator {
}            public class ComponentActivity extends androidx.core.app.ComponentActivity implementsLifecycleOwner,ViewModelStoreOwner,SavedStateRegistryOwner,OnBackPressedDispatcherOwner {private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);public Lifecycle getLifecycle() {return mLifecycleRegistry;}            
}           
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,ViewModelStoreOwner, SavedStateRegistryOwner {
}            

ComponentActivity和Fragment已经默认实现了LifecycleOwner接口。(代表有生命周期)

LifecycleOwner

那什么是LifecycleOwner呢?实现LifecycleOwner接口就表示这是个有生命周期的类他有一个getLifecycle()方法是必须实现的。

 //一个具有Android生命周期的类。自定义组件可以使用这些事件来处理生命周期更改,而无需在Activity或Fragment中实现任何代码。
@SuppressWarnings({"WeakerAccess", "unused"})
public interface LifecycleOwner {/*** Returns the Lifecycle of the provider.*/@NonNullLifecycle getLifecycle();
}

从以上源码可知,Activity和Fragment已经替我们实现了被观察者应该实现的那一部分代码。因此,我们不需要再去实现这部分代码。当我们希望监听Activity的生命周期时,只需要实现观察者那一部分的代码,即让自定义组件实现LifecycleObserver接口即可。该接口没有接口方法,无须任何具体实现。

对于前面提到的监听位置的例子。可以把MyLocationListener实现LifecycleObserver,然后在Lifecycle(Activity/Fragment)onCreate方法中初始化。这样MyLocationListener就能自行处理生命周期带来的问题。

自定义LifecycleOwner

  • 如果想在自定义的类中实现LifecyclerOwner,就需要用到LifecycleRegistry类,并且需要自行发送Event:
class MyActivity : Activity(), LifecycleOwner {private lateinit var lifecycleRegistry: LifecycleRegistryoverride 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

/*** Marks a class as a LifecycleObserver. It does not have any methods, instead, relies on* {@link OnLifecycleEvent} annotated methods.* @see Lifecycle Lifecycle - for samples and usage patterns.//-------------* 将类标记为LifecycleObserver。它没有任何方法,而是依赖于*{@link OnLifecycleEvent}注释的方法。*@请参阅生命周期-了解示例和使用模式。*/
@SuppressWarnings("WeakerAccess")
public interface LifecycleObserver {}

注释上写的很明白,该接口依赖OnLifecycleEvent的注解方法

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnLifecycleEvent {Lifecycle.Event value();
}
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
}

示例改进

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// lifecycle是LifecycleOwner接口的getLifecycle()方法得到的lifecycle.addObserver(MyObserver()) }
}

在Activity中只需要引用MyObserver即可,不用再关心Activity生命周期变化对该组件所带来的影响。生命周期的管理完全交给MyObserver内部自行处理。在Activity中要做的只是通过getLifecycle().addObserver()方法,将观察者与被观察者绑定起来。

class MyObserver : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)fun connectListener() {...//填写逻辑业务代码}@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)fun disconnectListener() {...//填写逻辑业务代码}
}

上面的lifecycle.addObserver(MyObserver()) 的完整写法应该是aLifecycleOwner.getLifecycle().addObserver(new MyObserver())aLifecycleOwner一般是实现了LifecycleOwner的类,比如Activity/Fragment

internal class MyLocationListener(private val context: Context,private val lifecycle: Lifecycle,private val callback: (Location) -> Unit): LifecycleObserver {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}
}
  • 对于组件中那些需要在页面生命周期发生变化时得到通知的方法,我们需要在这些方法上使用==@OnLifecycleEvent(Lifecycle.Event.ON_XXX)==标签进行标识。这样,当页面生命周期发生变化时,这些被标识过的方法便会被自动调用。

LifeCycle完美解决了组件对页面生命周期的依赖问题,使组件能够自己管理其生命周期,而无须在页面中对其进行管理。这无疑大大降低了代码的耦合度,提高了组件的复用程度,也杜绝了由于对页面生命周期管理的疏忽而引发的内存泄漏问题,这在项目工程量大的情况下是非常有帮助的。

使用LifecycleService解耦Service与组件

拥有生命周期概念的组件除了Activity和Fragment,还有一个非常重要的组件是Service。为了便于对Service生命周期的监听,达到解耦Service与组件的目的,Android提供了一个名为LifecycleService的类。该类继承自Service,并实现了LifecycleOwner接口。与Activity/Fragment类似,它也提供了一个名为getLifecycle()的方法供我们使用。

  • 想要使用LifecycleService必须先增加lifecycle-service的依赖:
implementation 'androidx.lifecycle:lifecycle-service:2.3.1'

结构:

public class LifecycleServiceextends Service implements LifecycleOwner
java.lang.Objectandroid.content.Contextandroid.content.ContextWrapperandroid.app.Serviceandroidx.lifecycle.LifecycleService 

源码:

public class LifecycleService extends Service implements LifecycleOwner {private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);@CallSuper@Overridepublic void onCreate() {mDispatcher.onServicePreSuperOnCreate();super.onCreate();}@CallSuper@Nullable@Overridepublic IBinder onBind(@NonNull Intent intent) {mDispatcher.onServicePreSuperOnBind();return null;}@SuppressWarnings("deprecation")@CallSuper@Overridepublic void onStart(@Nullable Intent intent, int startId) {mDispatcher.onServicePreSuperOnStart();super.onStart(intent, startId);}// this method is added only to annotate it with @CallSuper.// In usual service super.onStartCommand is no-op, but in LifecycleService// it results in mDispatcher.onServicePreSuperOnStart() call, because// super.onStartCommand calls onStart().@CallSuper@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@CallSuper@Overridepublic void onDestroy() {mDispatcher.onServicePreSuperOnDestroy();super.onDestroy();}@Override@NonNullpublic Lifecycle getLifecycle() {return mDispatcher.getLifecycle();}
}

整个应用进程的生命周期ProcessLifecycleOwner

具有生命周期的系统组件除Activity、Fragment、Service外,还有Application。很多时候,我们会遇到这样的需求:我们想知道应用程序当前处在前台还是后台,或者当应用程序从后台回到前台时,我们能够得到通知。有不少方案能够实现该需求,但都不够好。在此之前,Google并没有为该需求提供官方解决方案,直到LifeCycle的出现。

  • 需要先添lifecycle-process的依赖:
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'

源码:

/*** Class that provides lifecycle for the whole application process.* <p>* You can consider this LifecycleOwner as the composite of all of your Activities, except that* {@link Lifecycle.Event#ON_CREATE} will be dispatched once and {@link Lifecycle.Event#ON_DESTROY}* will never be dispatched. Other lifecycle events will be dispatched with following rules:* ProcessLifecycleOwner will dispatch {@link Lifecycle.Event#ON_START},* {@link Lifecycle.Event#ON_RESUME} events, as a first activity moves through these events.* {@link Lifecycle.Event#ON_PAUSE}, {@link Lifecycle.Event#ON_STOP}, events will be dispatched with* a <b>delay</b> after a last activity* passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner* won't send any events if activities are destroyed and recreated due to a* configuration change.** <p>* It is useful for use cases where you would like to react on your app coming to the foreground or* going to the background and you don't need a milliseconds accuracy in receiving lifecycle* events.*/
/**
翻译:
*为整个应用程序流程提供生命周期的类。
*您可以将此LifecycleOwner视为所有活动的组合,除了
*{@link Lifecycle。事件#ON_CREATE}将被调度一次,并且{@linkLifecycle。事件#ON_DESTROY}
*永远不会被派遣。其他生命周期事件将按照以下规则进行调度:
*ProcessLifecycleOwner将调度{@link Lifecycle。事件#ON_START},
*{@linkLifecycle.Event#ON_RESUME}事件,作为第一个活动在这些事件中移动。
*{@link Lifecycle。Event#ON_PAUSE},{@link Lifecycle。Event#ON_STOP},事件将与上次活动后的a延迟穿过他们。此延迟足够长,可以保证ProcessLifecycleOwner
*如果活动由于配置更改。
*它适用于您希望对应用程序进入前台或
*进入后台,在接收生命周期中不需要毫秒的准确性事件。
*/
@SuppressWarnings("WeakerAccess")
public class ProcessLifecycleOwner implements LifecycleOwner {

ProcessLifecycleOwner的使用方式与Activity、Fragment和Service是类似的,其本质也是观察者模式。由于我们要观察的是整个应用程序,因此,需要在Application中进行相关代码的编写。

class StApplication : Application() {companion object {private lateinit var instance: Applicationfun getInstance() = instance}override fun onCreate() {super.onCreate()instance = thisProcessLifecycleOwner.get().lifecycle.addObserver(MyApplicationObserver())}
}
class MyApplicationObserver : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)fun onCreate() {}// 前台出现时调用@OnLifecycleEvent(Lifecycle.Event.ON_START)fun onStart() {Log.e("xoliu", "onStart")}// 前台出现时调用@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)fun onResume() {Log.e("xoliu", "onResume")}// 退出到后台时调用@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)fun onPause() {Log.e("xoliu", "onPause")}// 退出到后台时调用@OnLifecycleEvent(Lifecycle.Event.ON_STOP)fun onStop() {Log.e("xoliu", "onStop")}
}
  • 当应用程序从后台回到前台,或者应用程序被首次打开时,会依次调用Lifecycle.Event.ON_STARTLifecycle.Event.ON_RESUME

  • 当应用程序从前台退到后台(用户按下Home键或任务菜单键),会依次调用Lifecycle.Event.ON_PAUSELifecycle.Event.ON_STOP。需要注意的是,这两个方法的调用会有一定的延后。这是因为系统需要为“屏幕旋转,由于配置发生变化而导致Activity重新创建”的情况预留一些时间。也就是说,系统需要保证当设备出现这种情况时,这两个事件不会被调用。因为当旋转屏幕时,你的应用程序并没有退到后台,它只是进入了横/竖屏模式而已。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/186328.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[跑代码]BK-SDM: A Lightweight, Fast, and Cheap Version of Stable Diffusion

Installation(下载代码-装环境) conda create -n bk-sdm python3.8 conda activate bk-sdm git clone https://github.com/Nota-NetsPresso/BK-SDM.git cd BK-SDM pip install -r requirements.txt Note on the torch versions weve used torch 1.13.1 for MS-COCO evaluation…

windows远程桌面登录,提示:“出现身份验证错误,要求的函数不受支持”

问题&#xff1a; windows登录远程桌面&#xff0c;提示&#xff1a;“出现身份验证错误&#xff0c;要求的函数不受支持”&#xff0c;如下图&#xff1a; 问题原因&#xff1a; windows系统更新&#xff0c;微软系统补丁的更新将 CredSSP 身份验证协议的默认设置进行了调…

Windows + docker + python + vscode : 使用容器docker搭建python开发环境,无需本地安装python开发组件

下载docker for Windows docker window下载 如果没有翻墙工具&#xff0c;可以该网盘中的docker 链接&#xff1a;https://pan.baidu.com/s/11zLy3e5kusZR-4m_Fq_cqg?pwdesmv 提取码&#xff1a;esmv 安装docker docker的安装会重启电脑&#xff0c;不要惊讶&#xff0c;且…

Unity 注释的方法

1、单行注释&#xff1a;使用双斜线&#xff08;//&#xff09;开始注释&#xff0c;后面跟注释内容。通常注释一个属性或者方法&#xff0c;如&#xff1a; //速度 public float Speed;//打印输出 private void DoSomething() {Debug.Log("运行了我"); } …

构建智能预约体验:深度解析预约系统源码的代码精髓

随着数字化时代的发展&#xff0c;预约系统在各行业中扮演着越来越重要的角色。本文将深入研究预约系统源码&#xff0c;通过代码示例分析其技术要点&#xff0c;为开发者提供实用的指导&#xff0c;助力构建智能、高效的预约体验。 技术栈综述 预约系统源码采用了现代化的技…

JAVEE初阶 多线程基础(四)

线程安全 一.线程安全存在的问题二.锁三.关于锁的理解四.关于锁操作混淆的理解4.1两个线程是否对同一对象加锁 一.线程安全存在的问题 为什么这里的count不是一百万呢?这就是线程所存在的不安全的问题,由于线程是抢占式执行,同时执行count,操作本质是三个指令 1.load 读取内存…

带大家做一个,易上手的家常炒鸡蛋

想做这道菜 先准备五个鸡蛋 然后将鸡蛋打到碗里面 然后 加小半勺盐 这个看个人喜好 放多少都没问题 不要太咸就好 将鸡蛋搅拌均匀 起锅烧油 油温热了之后 放三个干辣椒进去炒 干辣椒烧黑后 捞出来 味道就留在油里了 然后 倒入鸡蛋液 翻炒 注意翻炒 不要粘锅底 或者 一面糊…

南开大学与字节跳动研究人员推出开源AI工具ChatAnything:用文本描述生成虚拟角色

南开大学与字节跳动研究人员合作推出了一项引人注目的研究&#xff0c;发布了一种名为ChatAnything的全新AI框架。该框架专注于通过在线方式生成基于大型语言模型&#xff08;LLM&#xff09;的角色的拟人化形象&#xff0c;从而创造具有定制视觉外观、个性和语调的人物。 简答…

深度解析 Spring Security 自定义异常失效问题:源码剖析与解决方案

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

设计模式之装饰模式(2)--有意思的想法

目录 背景概述概念角色 基本代码分析❀❀花样重难点聚合关系认贼作父和认孙做父客户端的优化及好处继承到设计模式的演变过程 总结 背景 这是我第二次写装饰模式&#xff0c;这一次是在上一次的基础上进一步探究装饰模式&#xff0c;这一次有了很多新的感受和想法&#xff0c;也…

BUUCTF john-in-the-middle 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 注意&#xff1a;得到的 flag 请包上 flag{} 提交 密文&#xff1a; 下载附件&#xff0c;解压得到john-in-the-middle.pcap文件。 解题思路&#xff1a; 1、双击文件&#xff0c;打开wireshark。 看到很多http流…

基于springboot实现的在线考试系统

一、系统架构 前端&#xff1a;html | js | css | jquery | bootstrap 后端&#xff1a;springboot | springdata-jpa 环境&#xff1a;jdk1.7 | mysql | maven 二、 代码及数据库 三、功能介绍 01. 登录页 02. 管理员端-课程管理 03. 管理员端-班级管理 04. 管理员端-老师管理…

AT89S52单片机智能寻迹小车自动红外避障趋光检测发声发光设计

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;寻迹 获取完整说明报告源程序数据 小车具有以下几个功能&#xff1a;自动避障功能&#xff1b;寻迹功能&#xff08;按路面的黑色轨道行驶&#xff09;&#xff1b;趋光功能&#xff08;寻找前方的点光源并行驶到位&…

C++ ini配置文件的简单读取使用

ini文件就是简单的section 下面有对应的键值对 std::map<std::string, std::map<std::string, std::string>>MyIni::readIniFile() {std::ifstream file(filename);if (!file.is_open()) {std::cerr << "Error: Unable to open file " << …

以STM32CubeMX创建DSP库工程方法一

以STM32CubeMX创建DSP库工程方法 略过时钟树的分配和UART的创建等&#xff0c;直接进入主题生成工程文件 它们中的文件功能如下&#xff1a; 1&#xff09;BasicMathFunctions 基本数学函数&#xff1a;提供浮点数的各种基本运算函数&#xff0c;如向量加减乘除等运算。 2&…

【MATLAB】EWT分解+FFT+HHT组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 EWTFFTHHT组合算法是一种广泛应用于信号处理领域的算法&#xff0c;它结合了经验小波变换&#xff08;Empirical Wavelet Transform&#xff0c;EWT&#xff09;、快速傅里叶变换&#x…

SpringBoot查询指定范围内的坐标点

使用Redis geo实现 redis geo是基于Sorted Set来实现的 Redis 3.2 版本新增了geo相关命令&#xff0c;用于存储和操作地理位置信息。提供的命令包括添加、计算位置之间距离、根据中心点坐标和距离范围来查询地理位置集合等&#xff0c;说明如下: geoadd&#xff1a;添加地理…

DCDC前馈电容与RC串并联电路

一、RC串并联电路特性分析 1、RC串联电路 RC 串联的转折频率&#xff1a; f01/&#xff08;2πR1C1&#xff09;&#xff0c;当输入信号频率大于 f0 时&#xff0c;整个 RC 串联电路总的阻抗基本不变了&#xff0c;其大小等于 R1。 2、RC并联电路 RC 并联电路的转折频率&…

02、Tensorflow实现手写数字识别(数字0-9)

02、Tensorflow实现手写数字识别&#xff08;数字0-9&#xff09; 01、Tensorflow实现二元手写数字识别&#xff08;二分类问题&#xff09; 02、Tensorflow实现手写数字识别&#xff08;数字0-9&#xff09; 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&…

zookeeper集群和kafka集群

&#xff08;一&#xff09;kafka 1、kafka3.0之前依赖于zookeeper 2、kafka3.0之后不依赖zookeeper&#xff0c;元数据由kafka节点自己管理 &#xff08;二&#xff09;zookeeper 1、zookeeper是一个开源的、分布式的架构&#xff0c;提供协调服务&#xff08;Apache项目&…