【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.hqwc.cn/news/231151.html

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

相关文章

分割掩模 VS 掩膜

掩膜 Mask分割掩模 Segmentation Mask总结示例 掩膜 Mask “掩膜” 是指一种用于 标识或遮蔽图像中特定区域 的 图像。 在图像处理中&#xff0c;掩膜通常是一个 二值图像&#xff0c;其中的 像素值为 0 或 1。binary Mask 叫做二元掩膜&#xff0c;如下图所示&#xff1a; 这…

Ubuntu上的常用软件配置

《立冬》——李白 〔唐代〕 冻笔新诗懒写&#xff0c;寒炉美酒时温。 醉看墨花月白&#xff0c;恍疑雪满前村。 对于Android开发者而言&#xff0c;折腾Android源码那是其乐无穷啊。但是有时候在Linux系统下会很不方便&#xff0c;这里特此记录一下常用的软件配置&#xff0c;希…

图面试专题

一、概念 和二叉树的区别&#xff1a;图可能有环 常见概念 顶点&#xff08;Vertex&#xff09;&#xff1a; 图中的节点或点。边&#xff08;Edge&#xff09;&#xff1a; 顶点之间的连接线&#xff0c;描述节点之间的关系。有向图&#xff08;Directed Graph&#xff09;&…

BUUCTF-pwn-ciscn_2019_ne_51

简单查看保护&#xff1a; 32为程序没有canary没有PIE&#xff0c;应该是简单的栈溢出。我们照着这个思路去找溢出点在哪&#xff0c;运行下程序看看什么情况&#xff1a; 程序上来是输入一个密码验证。随便输入下错误直接退出。因此我们需要到IDA中看看怎么回事&#xff1a; 主…

Linux详解——安装JDK

目录 一、下载jdk 二、tar包安装 三、rpm包安装 一、下载jdk 1.下载jdk https://www.oracle.com/technetwork/java/javase/downloads/index.html 2.通过CRT|WinSCP工具将jdk上传到linux系统中 二、tar包安装 # 1.将JDK解压缩到指定目录 tar -zxvf jdk-8u171-linux…

报错解决:You may need an additional loader to handle the result of these loaders.

报错信息如下 vue 项目 Module parse failed: Unexpected token (1:9) File was processed with these loaders:* ./node_modules/vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js* ./node_modules/babel-loader/lib/index.js* ./node_modules/eslint-loader/in…

【R语言】——相关性分析和热图绘制

本期介绍了利用R语言进行相关性分析和数据的可视化的方法。 一、什么是相关性分析&#xff1f; 相关性分析是指对两个或多个具备相关性的变量元素进行分析&#xff0c;从而衡量两个变量因素的相关密切程度。相关性的元素之间需要存在一定的联系或者概率才可以进行相关性分析。…

矩阵代数与MATLAB实现(特征值、广义特征值、酋矩阵、)

矩阵代数的相关知识 目录 一、特征值与特征向量 1、特征值与特征向量 2、MATLAB计算 二、广义特征值与广义特征向量 1、广义特征值与广义特征向量 2、MATLAB计算 三、酋矩阵 1、酋矩阵 2、MATLAB计算 四、未完待续 总结 提示&#xff1a;以下是本篇文章正文内容&…

网工内推 | 中高级网工,IE认证优先,带薪年假,五险一金

01 敏于行&#xff08;北京&#xff09;科技有限公司 招聘岗位&#xff1a;高级网络开发工程师 职责描述&#xff1a; 1、负责设计、参与数字身份安全中网络安全模块相关项目&#xff08;零信任SDP、VPN等&#xff09;&#xff1b; 2、深入研究和理解网络底层协议和通信机制&…

Aruba无线控制器新增加AP

1、将网线连接上AP的Eth端口&#xff0c;console线也连接上console口 2、在console后台可以看到AP获取到的IP地址 3、确认网络可以联通&#xff0c;通过https访问web界面 AP205默认账号密码&#xff1a;admin AP505账号为admin&#xff0c;密码为设备SN 4、右上角点击"维…

手势识别4:C/C++实现手部检测和手势识别(含源码下载)

手势识别4&#xff1a;C/C实现手部检测和手势识别(含源码下载) 目录 手势识别4&#xff1a;C/C实现手部检测和手势识别(含源码下载) 1. 前言 2. 手势识别模型&#xff08;YOLOv5&#xff09; &#xff08;1&#xff09;手势识别模型训练 &#xff08;2&#xff09;将Pyto…

Mac单独修改应用语言

方法1: 方法2: defaults write com.microsoft.Excel AppleLanguages ("zh-cn") defaults write com.microsoft.Word AppleLanguages ("zh-cn")参考&#xff1a;https://www.zhihu.com/question/24976020