Compose 生命周期和副作用

文章目录

  • Compose 生命周期和副作用
    • 生命周期
    • 副作用API
      • DisposableEffect
      • SIdeEffect
      • LaunchedEffect
      • rememberCoroutineScope
      • rememberUpdatedState
      • snapshotFlow
      • produceState
      • derivedStateOf

Compose 生命周期和副作用

生命周期

在这里插入图片描述

  • OnActive:添加到视图树。即Composable被首次执行,在视图树上创建对应的节点。
  • OnUpdate:重组。Composable跟随重组不断执行,更新视图树上的对应节点。
  • OnDispose:从视图树移除。Composable不再被执行,对应节点从视图树上移除。

Composable在角色上更加类似于传统视图的View,所以没有Activity或者Fragment那样的前后台切换的概念,生命周期相对简单。

副作用API

副作用(Side-Effects):指在 Composable 函数中执行的可能会产生外部影响或依赖于外部资源的操作。如,访问数据库、网络请求、文件操作、弹出Toast、保存本地文件、访问远程或本地数据等。

重组可能会造成Composable频繁反复执行,副作用不应该跟随重组反复执行的。

为了处理副作用,Android Compose 提供了一系列副作用API。

DisposableEffect

DisposableEffect 可以感知 Composable 的 onActive 和 onDispose,允许通过副作用完成一些预处理和收尾处理。

@Composable
fun LifecyclePage() {
    var counter by remember { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("Counter: ${counter}")
        Row {
            Button(onClick = { counter-- }) {
                Text("-")
            }
            Button(onClick = { counter++ }) {
                Text("+")
            }
        }
    }

    DisposableEffect(Unit) {
        Log.e("TAG", "预处理")
        counter = 100

        onDispose {
            Log.e("TAG", "销毁处理")
        }
    }
}

SIdeEffect

SIdeEffect 会在重组成功时执行,不适合处理那些耗时或者异步的副作用逻辑。

@Composable
fun LifecyclePage() {
    var counter by remember { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("Counter: ${counter}")
        Row {
            Button(onClick = { counter-- }) {
                Text("-")
            }
            Button(onClick = { counter++ }) {
                Text("+")
            }
        }
    }

    SideEffect {
        Log.e("TAG", "hello 重组了")
    }
}

LaunchedEffect

用于异步操作。

当 Composable 进入 OnActive 时,LaunchedEffect 会启动协程执行 block 中的内容,可以在其中启动子协程或者调用挂起函数。当Composable 进入 OnDispose 时,协程会自动取消,因此 LaunchedEffect 不需要实现OnDispose{…}。

@Composable
fun LifecyclePage() {
    var counter by remember { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("Counter: ${counter}")
        Row {
            Button(onClick = { counter-- }) {
                Text("-")
            }
            Button(onClick = { counter++ }) {
                Text("+")
            }
        }
    }
    
    LaunchedEffect(Unit) {
        async {
            delay(2000L)
            Log.e("TAG", "异步处理")
            counter = 2000
        }
    }
}

rememberCoroutineScope

协程操作。

LaunchedEffect 虽然可以启动协程,但是只能在 Composable 中调用。如果想在非 Composable 中使用协程,如点击事件中,可以使用 rememberCoroutineScope。

rememberCoroutineScope 会返回一个 CoroutineScope,并在 OnDispose 时自动取消。

@Composable
fun LifecyclePage() {
    var counter by remember { mutableStateOf(0) }
    val scope = rememberCoroutineScope()

    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("Counter: ${counter}")      
        Button(onClick = {
            scope.launch {
                Log.e("TAG", "协程操作")
                counter = 3000
            }
        }) {
            Text("协程操作")
        }
    } 
}

rememberUpdatedState

监听状态最新状态。

rememberUpdatedState的实现就明白其中原理了,其实就是remember和mutableStateOf的组合使用

@Composable
fun LifecyclePage() {
    var counter by remember { mutableStateOf(0) }
    val updateCounter by rememberUpdatedState(newValue = counter)

    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("Counter: ${counter}")
        Row {
            Button(onClick = { counter-- }) {
                Text("-")
            }
            Button(onClick = { counter++ }) {
                Text("+")
            }
        } 
        Text("监听最新状态:${updateCounter}")
    }
}

snapshotFlow

snapshotFlow 可以把 Compose 的 State 状态对象转成协程的 Flow。

@Composable
fun LifecyclePage() {
    var time by remember { mutableStateOf("${System.currentTimeMillis()}") }
    val flow = snapshotFlow { time }

    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Button(onClick = {
            time = "${System.currentTimeMillis()}"
        }) {
            Text("更新")
        }
    }

    LaunchedEffect(Unit) {
        flow.collect {
            Log.e("TAG", "snapshotFlow: ${it}")
        }
    }
}

produceState

SideEffect 常用来将Compose的State暴露给外部使用,而produceState则相反,可以将一个外部的数据源转成State。外部数据源可以是一个LiveData或者RxJava这样的可观察数据,也可以是任意普通的数据类型。

data class Person(val name: String, val age: Int, val time: Long)

@Composable
fun MyProduceState() {
    var name by remember { mutableStateOf("小明") }
    var age by remember { mutableStateOf(18) }

    val personState by produceState(
        initialValue = Person(name, age, System.currentTimeMillis()),
        name,
        age
    ) {
        value = Person(name, age, System.currentTimeMillis())
    }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Button(onClick = { name = "小红" }) {
            Text("修改name")
        }
        Button(onClick = { age = 19 }) {
            Text("修改age")
        }
        Text("produceState: ${personState}")
    }
}

说明:修改 name 或 age 都会触发 produceState。

derivedStateOf

derivedStateOf用来将一个或多个State转成另一个State。derivedStateOf{…}的block中可以依赖其他State创建并返回一个DerivedState,当block中依赖的State发生变化时,会更新此DerivedState,依赖此DerivedState的所有Composable会因其变化而重组。

@Composable
fun MyDerivedStateOf() {
    var postList by remember { mutableStateOf(listOf("a", "b", "c", "d", "e")) }
    var keyword by remember { mutableStateOf("") }
    val result by remember {
        derivedStateOf { postList.filter { it.contains(keyword, false) } }
    }
    Text("过滤:${result}")
    Button(onClick = { postList = listOf("1", "2", "3", "4", "5") }) {
        Text("修改List")
    }
    OutlinedTextField(value = keyword, onValueChange = { keyword = it }, label = { Text("请输入") })
}

说明:当 postList 或 keyword 方式变化时,derivedStateOf 都会重新计算,result 也就更新了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有哪些有效的复习方法可以帮助备考软考?

软考目前仍然是一个以记忆为主、理解为辅的考试。学过软考的朋友可能会感到困惑,因为软考的知识在日常工作中有许多应用场景,需要理解的地方也很多。但为什么我说它是理解为辅呢?因为这些知识点只要记住了,都不难理解,…

快速传输大文件:手机电脑互传文件的最佳解决方案

无论是工作还是生活,我们都可能需要将照片、视频、音乐或其他类型的文件从一台设备发送到另一台设备。然而,由于网络速度的限制,传统的文件传输方法可能会非常耗时。那么,有没有一种快速传输大文件的解决方案呢?答案是…

Linux网络编程(三)IO复用一 select系统调用

I/O复用使得程序能同时监听多个文件描述符。在以下场景中需要使用到IO复用技术: 客户端程序要同时处理多个socket,非阻塞connect技术客户端程序要同时处理用户输入和网络连接,聊天室程序TCP服务器要同时处理监听socket和连接socket服务器要同…

【JAVA |数组】数组定义与使用、常见的Arrays类介绍

目录 一、前言 二、数组的创建和初始化 三、数组的使用 四、数组是引用类型 1.JVM的内存分配 2.与引用类型变量 3.null 五、二维数组 六、Java中Arrays类的常用方法 1. Arrays.fill ->填充数组 2. Arrays.sort ->数组排序 3. Arrays.toString ->数组打印 …

数据中台:企业数字化转型的驱动力量_光点科技

在当今数字化快速发展的时代,企业正积极寻求转型升级的新路径。在这个过程中,数据中台以其独特的功能和价值,逐渐成为了企业数字化转型的关键驱动力。本文将深入探讨数据中台的角色、架构及其在企业中的应用,以期为企业的数字化转…

十个数据安全最佳实践:保护数据的简单方法

在德迅云安全将介绍数据安全的主要原则,并了解适用于大多数行业的 10 种数据安全最佳实践,以及云端安全检测的重要性。 数据威胁和维护数据安全的好处 什么是数据安全? 数据安全是旨在保护组织敏感资产的流程和工具的组合。有价值的数据在…

多核DSP并行计算跨平台通信解决方案

并行计算的核心是计算节点以及节点间的通信与协调机制。OpenMP虽然给开发者提供了极易上手的增量式开发方式,但是OpenMP在与复杂架构的MCSDK结合后,工具与代码产生了大量不可调试的黑盒子,更是决定了它不能用于关键任务领域,如军工…

C语言(指针)1

Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注收藏,欢迎欢迎~~ 💥个人主页:小羊在奋斗 💥所属专栏:C语言 本系列文章为个人学习笔记&#x…

用python写个控制MicroSIP自动拨号和定时呼叫功能(可用在小型酒店叫醒服务)

首先直接上结果吧,MicroSIP 助手,控制MicroSIP自动拨号,定时呼叫的非常实用小工具! 在使用MicroSIP 助手之前,我们需要了解MicroSIP是什么,MicroSIP是一个SIP拨号软件,支持注册任意SIP平台实现拨…

Linux学习笔记:信号

信号 在Linux中什么是信号信号的产生方式硬件产生的信号软件产生的信号异常产生的信号 进程对信号的处理信号的保存信号方法更改函数signal信号处理的更改恢复默认信号忽略 信号的管理信号集 sigset_t对信号集的操作 信号的捕捉过程 在Linux中什么是信号 在 Linux 系统中&…

Python中tkinter编程入门1

1 tkinter库简介 tkinter是Python的标准库,用来进行GUI(Graphical User Interface,图形用户界面)编程。 2 导入tkinter库 tkinter是Python默认的GUI库,因此,IDLE中已经包含了该库,使用时无需…

在uniapp中如何安装axios并解决跨域问题

目录 1、安装axios 2、导入 3、使用(发请求) 2.解决跨域问题 1.为什么要解决跨域问题? 2.前端如何解决跨域问题? 1、安装axios npm install axios 2、导入 在main.js中导入使用 import axios from axios; // 创建一个名…

男士内裤什么品牌质量好?男士内裤选购指南攻略分享

有很多小伙伴认为男士内裤只是穿在里面的,只要能穿就不讲究了。但实际上选择一些质量不好的男士内裤会让穿着舒适性十分不佳,同时还会因为不具备抗菌效果而滋生细菌,导致出现健康问题。 最近我也是深入研究了一番关于男士内裤,今天…

旺店通·企业奇门与金蝶云星空对接集成订单查询打通销售订单新增

旺店通企业奇门与金蝶云星空对接集成订单查询打通销售订单新增 对接源平台:旺店通企业奇门 慧策最先以旺店通ERP切入商家核心管理痛点——订单管理,之后围绕电商经营管理中的核心管理诉求,先后布局流量获取、会员管理、仓库管理等其他重要经营模块。慧策…

该怎么发外贸开发信才能瞄准大客户?

1.要知道80%的业务源自于大客户,要合理利用自己的时间。其实我自己发邮件一直都是粗发模式,效果也还可以,主要是因为我的客户都是展会上的,所以拒收和失败率会很低,而且客户意向度一直很高,但是花费的时间精…

泉州晋江厦门拉货最便宜的7个方式,建议收藏

众所周知,搬家、拉货的时间长、距离长,运费也比较贵。面对不菲的费用,很多人会比较谨慎,先网上搜搬家攻略,一番对比以后,找到最便宜的运输方式。那怎么运输最便宜最放心呢? 方式一:找…

[MDK] 介绍STM32使用C和C++混合编程的方法

目录 [MDK] 介绍STM32使用C和C混合编程的方法前言业务场景步骤1基础工程步骤2写代码步骤3添加cpp文件步骤4配置与编译上机现象后记 [MDK] 介绍STM32使用C和C混合编程的方法 前言 搞单片机编程大多数还是使用MDK编程,自己对MDK这个软件也比较熟悉,在网络…

【RAG 论文】Dense X 检索:将“命题”作为检索粒度

论文:Dense X Retrieval: What Retrieval Granularity Should We Use? ⭐⭐⭐⭐ Code: github.com/ct123098/factoid-wiki 文章目录 一、论文速读二、命题(Proposition)三、FactoidWiki四、实验及分析4.1 Passage Retrieval 任务4.2 Open-Do…

前端css中径向渐变(radial-gradient)的使用

前端css中径向渐变的使用 一、前言二、主要内容说明(一)、径向渐变的形状1.椭圆形渐变(ellipse),源码12.源码1运行效果3.圆形渐变(circle),源码24.源码2运行效果 (二&…

遇到螺纹连接过程中的软连接,怎么办?——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 在螺纹连接过程中遇到软连接时,首先需要明确软连接的概念及其特点。软连接通常指的是在螺栓拧紧过程中,由于紧固件与被连接件之间的材料、表面状况或装配工艺等因素,导致拧紧力矩不能…