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()
        }
    }
}
相关推荐
阿巴斯甜4 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴7 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab19 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android