降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles

公众号「稀有猿诉」        原文链接 降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles

Jetpack Compose是一个独立的声明式UI框架,它并不受限于任何操作系统平台,从框架定位的角度来讲,它是跨平台的,也应该要跨平台。但是我们的应用程序必然是为某些操作系统平台(后面简称平台Platform)构建的,也就是说要运行在某些平台上面。这就免不了要与平台进行打交道。这篇文章将以Android平台为例,学习在Compose中如何处理平台的生命周期事件。

banner

感知平台生命周期事件

对于移动应用程序来说,感知平台的生命周期是非常重要的,比如最为典型的场景,对于一个新闻消息类的应用来说,当首次进入页面的时候肯定 要刷新拉取最新的消息,当用户切换到另外一个应用时,比如接了个电话,或者分享,之后再回到你的应用页面,这时也应该主动刷新消息,而不是要等着用户手动的去点击刷新按扭;再比如说当使用了硬件资源(位置,Camera或者Sensors等)时,更是要当离开应用页面的时候就应该立即释放硬件,以停止对硬件资源的占用。

从前面的文章降Compose十八掌之『损则有孚』| Lifecycle中我们了解到Composable本身的生命周期与平台是无关的且非常不一致,光靠Compose自己的节奏是无法感知到在平台生命周期事件的。这就需要我们使用一些桥接工具来感知平台生命周期事件,以能让我们针对感兴趣的事件执行一些操作。

生命周期事件副作用函数(LifecycleEffects)

幸运的是Jetpack组件中的lifecycle已经添加了对Compose的支持,定义了一些生命周期副作用函数,在这些副作用函数中可以针对 不同的事件设置代码块,当相应的生命周期发生时就会执行这些代码块:

LifecycleEventEffect(Lifecycle.Event.ON_START) {// onStar时执行一些操作
}

上面的代码就是指定要在onStart时做一些事情。需要注意的是,无法监听onDestroy(即事件Lifecycle.Event.ON_DESTROY),因为Compose的组合会在onDestroy之前就结束了。

除了上面的用法之外,还有更为为方便的LifecycleStartEffect和LifecycleResumeEffect可以直接使用,它们是针对onStart/onStop和onResume/onPause两对事件的,因为生命周期中最为常用的就是这四个事件了:

LifecycleStartEffect {// onStart中需要做的事情onStopOrDispose {// onStop需要做的事情}
}LifecycleResumeEffect {// onResume需要做的事情onPauseOrDispose {// onPause需要做的事}
}

需要注意,这两个副作用函数是针对事件对的,也就是说必须要带着后面的onStopOrDispose和onPauseOrDispose。如果仅对onStart感兴趣,而无须在onStop中做清理,那么应该直接使用LifecycleEventEffect(Lifecycle.Event.ON_START) {}(对于onResume也是同理)。

扩展阅读:

  • Managing Lifecycles Events on Jetpack Compose
  • Integrate Lifecycle with Compose

监听生命周期事件

除了直接使用生命周期副作用函数以外,也可以用lifecycle原生的方式,直接向LifecycleOwner注册一个LifecycleEventObserver来监听生命周期。通过Compose提供的LifeCycleOwner.current可以获得当前的LifecycleOwner,然后向其注册一个LifecycleEventObserver,当平台生命周期发生变化时,就会带着事件类型回调给监听者,监听者可以针对感兴趣的事件做操作。还需要注意的是,需要在组合结束(离开)时反注册observer,因此这里要用DisposableEffect。对于副作用函数不熟悉的同学可以去复习一下降Compose十八掌之『龙战于野』| Side Effects。

来看个简单的示例:

val lifecycleOwner = LocalLifecycleOwner.currentDisposableEffect(lifecycleOwner) {val observer = LifecycleEventObserver { _, event ->when (event) {Lifecycle.Event.ON_CREATE -> { /* onCreate */ }Lifecycle.Event.ON_START -> { /* onStart */ }Lifecycle.Event.ON_RESUME -> { /* onResume */ }Lifecycle.Event.ON_PAUSE -> { /* onPause */ }Lifecycle.Event.ON_STOP -> { /* onStop */ }Lifecycle.Event.ON_DESTROY -> { /* onDestroy */ }Lifecycle.Event.ON_ANY -> { /* Any event */ }else -> {}}}lifecycleOwner.lifecycle.addObserver(observer)onDispose {lifecycleOwner.lifecycle.removeObserver(observer)}}

这样就可以监听到生命周期事件,然后针对不同的事件做相应的操作。

当然,如果事件不止做一件事情,或者说对事件的响应不光光是执行一些函数,可能还会有页面的修改,那么这时最好就是把事件保存为一个状态(State),更为方便:

    val lifecycleOwner = LocalLifecycleOwner.currentvar lifecycleEvent by remember { mutableStateOf(Lifecycle.Event.ON_ANY) }DisposableEffect(lifecycleOwner) {val observer = LifecycleEventObserver { _, event ->lifecycleEvent = event}lifecycleOwner.lifecycle.addObserver(observer)onDispose {lifecycleOwner.lifecycle.removeObserver(observer)}}LaunchedEffect(lifecycleEvent) {if (lifecycleEvent == Lifecycle.Event.ON_RESUME) {viewModel.refresh()}}Column() {if (lifecycleEvent == Lifecycle.Event.ON_RESUME) {Text("Welcome back")}}

扩展阅读:

  • Android handle lifecycle event on Jetpack Compose Screen
  • Jetpack Compose — Making Composable lifecycle-aware
  • Jetpack Compose with Lifecycle-Aware Composables

以数据流的方式来处理生命周期事件

生命周期是由系统控制,不时发生变化,每次变化会向监听者回调一个事件,如果以一定的时间跨度来看待,这些事件就形成了一个数据流。因此,Lifecycle还提供了一个Flow接口,用以发送Lifecycle事件。可以当作状态(State)来收集此Flow,这样事件的变化就能驱动Compose的重组,进而感知到最新的生命周期事件:

val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow
val currentLifecycleState by stateFlow.collectAsState()// 或者
val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()

注意: 对于Flow不熟悉的同学可以复习一下包教包会的Kotlin Flow教程。

不要在ViewModel中感知生命周期

根据现代安卓开发架构原则,ViewModel应该处理与UI相关的业务逻辑,它应该独立于平台,因此,千万不要在ViewModel去感知生命周期,事实上你也做不到,因为ViewModel是没任何对平台的依赖的,非常独立的一个类型,也即拿不到LifecycleOwner。

当然了,有同学说,我可以从Compose的Composable中把LifecycleOwner当作参数传给ViewModel,但仍然强烈不建议这样做。深层的原因在于,ViewModel是独立于平台的,它有自己的生命周周期,平台的组件(如Activity)是由系统控制的,但ViewModel是由我们自己控制的,它的生命周期要长于平台的组件,也就是说ViewModel的生命周期要长于它持有的LifecycleOwner,故LifecycleOwner可能会变得过时(非当前的Activity了),同时因为被更长生命的ViewModel持有,原LifecycleOwner可能无法被回收而引发内存泄漏。

ViewModel只应该负责业务逻辑相关的事情,在Composable中监听生命周期事件很方便,也很合适,然后调用ViewModel的相应的接口(如refresh())即可。

总结

得益于Jetpack中的Lifecycle组件,在Compose中感知生命周期没有想像中的那样难。在实际项目中,推荐使用更符合Compose的方式,也即生命周期副作用函数以及事件数据流。如果仅是在某些生命周期事件发生时执行一些操作,那就用LifecycleEventEffect函数;如果不止一处需要使用事件,那就用事件数据流。

subscription

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

保护原创,请勿转载!

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

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

相关文章

OPenCV结构分析与形状描述符(5)查找图像中的连通组件的函数connectedComponents()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 connectedComponents 函数计算布尔图像的连通组件标签图像。 该函数接受一个具有4或8连通性的二值图像,并返回 N,即标签…

机器学习之 PCA降维

1.PCA 降维简介 主成分分析(Principal Component Analysis, PCA)是一种统计方法,用于在数据集中寻找一组线性组合的特征,这些特征被称为主成分。PCA 的目标是通过变换原始特征空间到新的特征空间,从而减少数据的维度&…

持久化分析

目录 介绍步骤WMI持久化分析注册表映像劫持IFEO持久化 介绍 1、WMI 的全称是 Windows Management Instrumentation,即 Windows 管理规范,在 Windows 操作系统中,随着 WMI 技术的引入并在之后随着时间的推移而过时,它作为一项功能…

Golang | Leetcode Golang题解之第387题字符串中的第一个唯一字符

题目: 题解: type pair struct {ch bytepos int }func firstUniqChar(s string) int {n : len(s)pos : [26]int{}for i : range pos[:] {pos[i] n}q : []pair{}for i : range s {ch : s[i] - aif pos[ch] n {pos[ch] iq append(q, pair{ch, i})} e…

用亚马逊云科技Graviton高性能/低耗能处理器构建AI向量数据库(上篇)

简介: 今天小李哥将介绍亚马逊推出的云平台4代高性能计算处理器Gravition,并利用该处理器构建生成式AI向量数据库。利用向量数据库,我们可以开发和构建多样化的生成式AI应用,如RAG知识库,特定领域知识的聊天机器人等。…

聚铭网络受邀成为ISC终端安全生态联盟首批成员单位

近日,在2024数博会这一行业盛会上,全国首个专注于终端能力的联盟——ISC终端安全生态联盟正式成立,聚铭网络受邀成为该联盟的首批成员单位之一。 ISC终端安全生态联盟由360集团发起,并联合20余家业内领先企业共同创立。联盟旨在通…

Rk3588 Android12 AIDL 开发

AIDL (Android Interface Definition Language) 和 HIDL (HAL Interface Definition Language) 都是 Android 系统中用于定义接口的工具,但它们有不同的用途和特性。 AIDL (Android Interface Definition Language) 用途: 主要用于应用程序之间的进程间…

Windows键盘快捷方式

键盘快捷方式是两个或多个键的组合,可用于执行通常需要鼠标或其他指针设备才能执行的任务。 使用键盘快捷方式你可以更轻松地与电脑进行交互,从而在使用 Windows 和其他应用时节省时间和精力。 大多数应用还提供加速键,以让你能够更轻松地使…

大数据-120 - Flink Window 窗口机制-滑动时间窗口、会话窗口-基于时间驱动基于事件驱动

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

自定义 SpringBoot Starter

文章目录 一、自定义 starter1.1 创建 maven 项目1.2 创建邮件配置属性类1.3 创建模拟邮件发送服务类1.4 创建自动配置类1.5 spring.factories 相关配置1.6 打包成依赖 二、测试项目2.1 创建项目2.2 application.yml 配置2.3 测试应用 参考资料 本文源码位于 java-demos/spring…

Restful风格接口开发

一、项目搭建 安装nestjs脚手架 // 安装nestjs脚手架 npm i nestjs/cli// 新建 nest new [名字]//选择要用的工具 npm / yarn / pnpm 文件信息: 【main.ts】: 入口文件,通过NestFactory(由nestjs/core库抛出的对象&#x…

微信小程序手写签名

微信小程序手写签名组件 该组件基于signature_pad封装,signature_pad本身是web端的插件,此处将插件代码修改为小程序端可用。 signature_pad.js /*!* Signature Pad v5.0.3 | https://github.com/szimek/signature_pad* (c) 2024 Szymon Nowak | Releas…

九盾叉车U型区域警示灯,高效照明和安全警示

叉车运作的环境比较复杂,在方便人们物流运输的同时也存在着很大的安全隐患,特别是叉车碰撞人的事故发生率很高,那我们该怎么在减少成本的同时又能避免碰撞事故的发生呢? 九盾叉车U型区域警示灯,仅需一盏灯安装在叉车尾…

十一 面向对象技术(考点篇)试题

A ;D,D。实际答案:C;D,D 考的很偏了。UML 2.0基础结构的设计目标是定义一个元语言的核心 UML 2.0 【InfrastructureLibrary】,通过对此核心的复用,除了可以定义一个自展的UML元模型,也可以 Infr…

基于IP子网的VLAN典型配置举例(H3C,其他厂商同理)

基于IP子网的VLAN典型配置举例 1. 组网需求 如下图所示,办公区的主机属于不同的网段192.168.5.0/24和192.168.50.0/24,Device C在收到来自办公区主机的报文时,根据报文的源IP地址,使来自不同网段主机的报文分别在指定的VLAN中传…

7、Django Admin删除默认应用程序

admin文件 from django.contrib.auth.models import User, Groupadmin.site.unregister(User) admin.site.unregister(Group) 显示效果: 前 后

基于FreeRTOS的STM32多功能手表

前言 项目背景 项目演示 使用到的硬件 项目原理图 目前版本实现的功能 设计到的freertos知识 实现思路 代码讲解 初始化GPIO引脚、配置时钟 蜂鸣器初始化以及软件定时器创建 系统默认创建的defaultTaskHandle 创建七个Task,代表七个功能 ShowTimeTask …

2024.9自然语言及语言处理设计开发工程师专项培训通知!

为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国务院印发《关于“十四五”数字经济发展规划》等有关工作的部署要求,深入实施人才强国战略和创新驱动发展战略,加强全国数字化人才队伍建设,持续推进人工智能从业人员…

Epoll 用法

Epoll 监听 EPOLL_CTL_DEL EPOLL_CTL_ADD epoll_event event event.events event.data.fd

双指针(3)_快慢指针_快乐数问题

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 双指针(3)_快慢指针_快乐数问题 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1.…