这一节主要了解一下Compose中使用rememberUpdatedState在Jetpack Compose开发中它是一个用于处理长效副作用与最新状态值之间矛盾的关键API。在不重启副作用的前提下确保内部逻辑始终能访问到最新的参数或状态值。简单总结如下:API:rememberUpdatedState:长期运行的副作用中始终引用最新的值同时避免副作用因为该值的变化而重启。栗子:import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay Composable fun CountdownDemo() { var tipsText by remember { mutableStateOf(初始提示文字) } var showCountdown by remember { mutableStateOf(false) } Column( modifier Modifier.padding(top 200.dp), verticalArrangement Arrangement.Center ) { Box(modifier Modifier.padding(20.dp)) { Button(onClick { tipsText 更新后的新提示文案; showCountdown true }) { Text(修改文字并开启倒计时) } } if (showCountdown) { CountdownTipDialog(tips tipsText) } } } Composable fun CountdownTipDialog(tips: String) { val latestTips rememberUpdatedState(tips) LaunchedEffect(Unit) { repeat(3) { delay(1000) Log.d(Test,倒计时日志${latestTips.value}) } } Column(modifier Modifier.padding(start 50.dp, top 100.dp)) { Text(text latestTips.value) } }import android.util.Log import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay data class Goods( val id: Int, val name: String, val price: String ) Composable fun CarouselDemo() { val goodsData remember { mutableStateListOf( Goods(1, 基础耳机, 99), Goods(2, 机械键盘, 199) ) } var itemClickAction by remember { mutableStateOf(Goods) - Unit({ Log.d(Test,旧逻辑 点击商品${it.name}) }) } var closeDialogAction by remember { mutableStateOf({ Log.d(Test,旧逻辑 弹窗关闭上报埋点旧接口) }) } var showCarouselDialog by remember { mutableStateOf(false) } Surface(modifier Modifier.fillMaxSize(), color MaterialTheme.colorScheme.background) { Column( modifier Modifier.padding(20.dp), verticalArrangement Arrangement.spacedBy(10.dp) ) { Button(onClick { goodsData.clear() goodsData.addAll(listOf( Goods(3, 电竞显示器, 1299), Goods(4, 无线鼠标, 149) )) }) { Text(更新商品列表) } Button(onClick { itemClickAction { Log.d(Test,新逻辑 跳转商品详情页${it.name}) } }) { Text(替换商品点击回调) } Button(onClick { closeDialogAction { Log.d(Test,新逻辑 弹窗关闭上报新版埋点接口) } }) { Text(替换弹窗关闭回调) } Button(onClick { showCarouselDialog true }) { Text(打开商品轮播弹窗) } } if (showCarouselDialog) { GoodsCarouselDialog( goodsList goodsData, onGoodsClick itemClickAction, onDialogClose { showCarouselDialog false closeDialogAction() } ) } } } Composable fun GoodsCarouselDialog( goodsList: ListGoods, onGoodsClick: (Goods) - Unit, onDialogClose: () - Unit ) { val latestGoodsList rememberUpdatedState(goodsList) val latestItemClick rememberUpdatedState(onGoodsClick) val latestCloseCallback rememberUpdatedState(onDialogClose) var currentIndex by remember { mutableIntStateOf(0) } var autoCloseCountdown by remember { mutableIntStateOf(30) } Box( modifier Modifier .fillMaxSize() .padding(40.dp), contentAlignment Alignment.Center ) { Card( modifier Modifier.fillMaxWidth(), shape RoundedCornerShape(12.dp) ) { Column(modifier Modifier.padding(16.dp)) { Row( modifier Modifier.fillMaxWidth(), horizontalArrangement Arrangement.SpaceBetween, verticalAlignment Alignment.CenterVertically ) { Text(商品轮播${autoCloseCountdown}s后自动关闭) Button(onClick latestCloseCallback.value) { Text(关闭) } } val currentGoods latestGoodsList.value.getOrNull(currentIndex) currentGoods?.let { goods - Box( modifier Modifier .fillMaxWidth() .size(180.dp) .clickable { latestItemClick.value(goods) }, contentAlignment Alignment.Center ) { Column(horizontalAlignment Alignment.CenterHorizontally) { Text(text goods.name, style MaterialTheme.typography.titleMedium) Text(text 价格${goods.price}元) } } } } } } LaunchedEffect(Unit) { while (true) { delay(2000) val list latestGoodsList.value if (list.isNotEmpty()) { currentIndex (currentIndex 1) % list.size } } } LaunchedEffect(Unit) { while (autoCloseCountdown 0) { delay(1000) autoCloseCountdown-- } latestCloseCallback.value() } DisposableEffect(Unit) { onDispose { Log.d(Test,弹窗销毁终止轮播倒计时协程执行最新关闭回调) latestCloseCallback.value() } } }注意:1 不要滥用,如果你希望状态变化时重启副作用请直接将该状态作为LaunchedEffect的Key不要使用rememberUpdatedState。2 解包State,rememberUpdatedState返回的是StateT。在Lambda或协程中使用时尽量使用by委托或直接访问 .value以确保读取到的是最新值。
Compose笔记(八十)--rememberUpdatedState
发布时间:2026/6/29 18:39:21
这一节主要了解一下Compose中使用rememberUpdatedState在Jetpack Compose开发中它是一个用于处理长效副作用与最新状态值之间矛盾的关键API。在不重启副作用的前提下确保内部逻辑始终能访问到最新的参数或状态值。简单总结如下:API:rememberUpdatedState:长期运行的副作用中始终引用最新的值同时避免副作用因为该值的变化而重启。栗子:import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay Composable fun CountdownDemo() { var tipsText by remember { mutableStateOf(初始提示文字) } var showCountdown by remember { mutableStateOf(false) } Column( modifier Modifier.padding(top 200.dp), verticalArrangement Arrangement.Center ) { Box(modifier Modifier.padding(20.dp)) { Button(onClick { tipsText 更新后的新提示文案; showCountdown true }) { Text(修改文字并开启倒计时) } } if (showCountdown) { CountdownTipDialog(tips tipsText) } } } Composable fun CountdownTipDialog(tips: String) { val latestTips rememberUpdatedState(tips) LaunchedEffect(Unit) { repeat(3) { delay(1000) Log.d(Test,倒计时日志${latestTips.value}) } } Column(modifier Modifier.padding(start 50.dp, top 100.dp)) { Text(text latestTips.value) } }import android.util.Log import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay data class Goods( val id: Int, val name: String, val price: String ) Composable fun CarouselDemo() { val goodsData remember { mutableStateListOf( Goods(1, 基础耳机, 99), Goods(2, 机械键盘, 199) ) } var itemClickAction by remember { mutableStateOf(Goods) - Unit({ Log.d(Test,旧逻辑 点击商品${it.name}) }) } var closeDialogAction by remember { mutableStateOf({ Log.d(Test,旧逻辑 弹窗关闭上报埋点旧接口) }) } var showCarouselDialog by remember { mutableStateOf(false) } Surface(modifier Modifier.fillMaxSize(), color MaterialTheme.colorScheme.background) { Column( modifier Modifier.padding(20.dp), verticalArrangement Arrangement.spacedBy(10.dp) ) { Button(onClick { goodsData.clear() goodsData.addAll(listOf( Goods(3, 电竞显示器, 1299), Goods(4, 无线鼠标, 149) )) }) { Text(更新商品列表) } Button(onClick { itemClickAction { Log.d(Test,新逻辑 跳转商品详情页${it.name}) } }) { Text(替换商品点击回调) } Button(onClick { closeDialogAction { Log.d(Test,新逻辑 弹窗关闭上报新版埋点接口) } }) { Text(替换弹窗关闭回调) } Button(onClick { showCarouselDialog true }) { Text(打开商品轮播弹窗) } } if (showCarouselDialog) { GoodsCarouselDialog( goodsList goodsData, onGoodsClick itemClickAction, onDialogClose { showCarouselDialog false closeDialogAction() } ) } } } Composable fun GoodsCarouselDialog( goodsList: ListGoods, onGoodsClick: (Goods) - Unit, onDialogClose: () - Unit ) { val latestGoodsList rememberUpdatedState(goodsList) val latestItemClick rememberUpdatedState(onGoodsClick) val latestCloseCallback rememberUpdatedState(onDialogClose) var currentIndex by remember { mutableIntStateOf(0) } var autoCloseCountdown by remember { mutableIntStateOf(30) } Box( modifier Modifier .fillMaxSize() .padding(40.dp), contentAlignment Alignment.Center ) { Card( modifier Modifier.fillMaxWidth(), shape RoundedCornerShape(12.dp) ) { Column(modifier Modifier.padding(16.dp)) { Row( modifier Modifier.fillMaxWidth(), horizontalArrangement Arrangement.SpaceBetween, verticalAlignment Alignment.CenterVertically ) { Text(商品轮播${autoCloseCountdown}s后自动关闭) Button(onClick latestCloseCallback.value) { Text(关闭) } } val currentGoods latestGoodsList.value.getOrNull(currentIndex) currentGoods?.let { goods - Box( modifier Modifier .fillMaxWidth() .size(180.dp) .clickable { latestItemClick.value(goods) }, contentAlignment Alignment.Center ) { Column(horizontalAlignment Alignment.CenterHorizontally) { Text(text goods.name, style MaterialTheme.typography.titleMedium) Text(text 价格${goods.price}元) } } } } } } LaunchedEffect(Unit) { while (true) { delay(2000) val list latestGoodsList.value if (list.isNotEmpty()) { currentIndex (currentIndex 1) % list.size } } } LaunchedEffect(Unit) { while (autoCloseCountdown 0) { delay(1000) autoCloseCountdown-- } latestCloseCallback.value() } DisposableEffect(Unit) { onDispose { Log.d(Test,弹窗销毁终止轮播倒计时协程执行最新关闭回调) latestCloseCallback.value() } } }注意:1 不要滥用,如果你希望状态变化时重启副作用请直接将该状态作为LaunchedEffect的Key不要使用rememberUpdatedState。2 解包State,rememberUpdatedState返回的是StateT。在Lambda或协程中使用时尽量使用by委托或直接访问 .value以确保读取到的是最新值。