compose 中的附带效应笔记一

通常情况下状态发生改变时想要更新UI,我们会使用 var value by remeber { mutableStateOf() }来创建一个可观察的状态数据。当state的数据发生改变以后,使用了state数据组件会发生重组,从而实现刷新。 但有些情况下,我们想要实现在可组合函数中执行一次网络请求,根据请求结果改变界面状态,或者执行挂起函数再改变界面状态。此时需要用到附带效应。

1.LaunchedEffect

launchedEffect主要作用是让你在Composable作用域里实现协程工作,来完成异步、耗时操作、网络请求等

kotlin 复制代码
@Composable
fun LunchedEffectTest(){
    var value by remeber{ mutableStateOf() }
    LaunchedEffect(key){ //key如果没有发生变化,则重组中不会启动新的协程
        while(true){
            delay(100)
            value++
        }
    }
    
    Text(text='${value}')
}

2.rememberCoroutineScope

LanchedEffect只能在composable作用域内调用,无法在按键点击回调等地方调用。rememberCoroutineScope可以在这些地方调用。

kotlin 复制代码
@Composable
fun rememberCoroutineScopeTest(){
    val scope = rememberCoroutineScope()
    Button(
        onclick={
            scope.launch{
                //模拟网络请求
            }
        }{
        Text("请求数据")
        }
    )
   
}

3.rememberUpdateState 只是辅助LaunchedEffect向外部(其他composeable方法)更新状态功能,用于在不同compose方法下LaunchedEffect的数据更新时提供更新数据。

kotlin 复制代码
@Composable
fun RemeberUpdateStateTest(){
    var name by remember { mutableStateOf("") }
    RemeberUpdateStateUI(name = name,onValueChanged = {
        name = it
    })
}

@Composable
fun RemeberUpdateStateUI(name:String,onValueChanged:(String) -> Unit){
    val nameUpdateState = remmberUpdateState(name)

    LaunchedEffect(key){  //key保持一致可以为true
        delay(1000)
        //Log.d("RemeberUpdateStateUI","$name") //正常情况下如果这里输入框输入完以后,这里最后结果并不是预期的,比如输入框111222,但是这里可能1000毫秒以后,name还是111,所以要用remeberUpdateState包装一下。
        //nameUpdateState 包装后的结果,这里获取的nameUpdateState对象中的值就是111222
    }
    
    OutLinedTextField(
        value = name,
        onValueChange = onValueChanged
    )
    
}

工作原理分析: rememberUpdatedState 的内部逻辑可以简化为以下核心思想:

  1. 创建一个持久的 MutableState 容器 :这个容器通过 remember 在重组中保持不变。
  2. 在每次重组时更新该容器的值 :无论 key 是否变化,只要可组合函数被调用,它就会将 newValue 更新到内部的 MutableState 中。
  3. 返回该容器的引用:效应内部通过这个稳定的引用,读取到的永远是最新存入的值。

其内部实现类似于以下的简化逻辑(概念模型):

kotlin 复制代码
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
    mutableStateOf(newValue)
}.apply { value = newValue }
// 注意:每次重组都会执行 `.apply { value = newValue }` 来更新值

4.SideEffect

SideEffect相当于DisposableEffect的简化,当不需要onDispose,不需要参数控制。compose操作非原子操作,重组中可能发生意外。

kotlin 复制代码
  @Composable
  fun sideEffectTest(user:User){
      val count = remember { mutableStateOf(0) }
      SideEffect{
          count = user.number
      }
      Text(text = count.value.toString,modifier = Modifier.clickable={
         count.value ++
      })
      
  }

5.DispoableEffect

DispoableEffect必须添加一个onDispose 方法,此方法一般用于处理资源清理和释放。另外DisposableEffect也带参数意义和LaunchedEffect的参数一样。

kotlin 复制代码
@Composable
fun DisposableEffectTest(dispatcher:OnBackPressDispather){
    val backCallback = remember { 
        object:OnBackPressCallback(true){
            override fun handleOnBackPressed(){
                //TODO
            }
        }
    }
    
    DisposableEffect(dispatcher){
        dispatcher.addCallback(backCallback)
        onDispose{
            backCallback.remove()
        }
    }
}
相关推荐
kdniao120 小时前
PHP 页面中如何实现根据快递单号查询物流轨迹?对接快递鸟在途监控 API 实操
android·开发语言·php
言之。20 小时前
MacBook M3 Pro:React Native 安卓开发
android·react native·react.js
感觉不怎么会21 小时前
Android 13 - 对讲app后台休眠后无法录音
android·linux
Minilinux20181 天前
Android系列之 屏幕触控机制(一)
android·屏幕触控·andorid touch·viewroot
冰语竹1 天前
Android学习-随笔(安装后设置路径)
android·学习
有位神秘人1 天前
Android中获取当前屏幕的宽高工具类
android
Yang-Never1 天前
Open GL ES -> 应用前后台、Recent切换,SurfaceView纹理贴图闪烁问题分析解决
android·开发语言·kotlin·android studio·贴图
liujun35121591 天前
camera开发,我对预览请求的理解
android
无法长大1 天前
Mac M1 环境下使用 Rust Tauri 将 Vue3 项目打包成 APK 完整指南
android·前端·macos·rust·vue3·tauri·打包apk
一只程序熊1 天前
uniappx 配置 uni.chooseLocation 地图
android·uni-app x