You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中LaunchedEffect内MutableState值重置问题求助

问题原因

你的问题出在LaunchedEffect的依赖项和变量捕获机制上:

  • LaunchedEffect(interactionSource) 仅在 interactionSource 变化时重新启动,content 参数更新不会触发它重组。
  • LaunchedEffect内部会捕获初始化时的 content 值,之后即使外部 content(即TextField的输入值)更新,内部的 content 变量仍保持首次启动时的空字符串,这就是日志#3、#4始终为空的原因。
  • 日志#1位于 composed 块内,每次Compose重组(比如TextField输入变化)都会执行,所以能显示最新的 content;而日志#2仅在LaunchedEffect首次启动时执行一次,因此只显示初始空值。
解决方案

使用 rememberUpdatedState 包装 content 参数,它能在不重启LaunchedEffect的前提下,让我们获取到最新的 content 值。修改后的完整代码如下:

@Composable
fun Modifier.timedClick(
    timeInMillis: Long = 2500,
    defaultPercentage: Float = 0f,
    content: String = "",
    onClick: (Float, String) -> Unit,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) = composed {
    var timeOfTouch = -1L
    // 用rememberUpdatedState跟踪最新的content值
    val latestContent = rememberUpdatedState(content)
    
    Log.d("BUTTON", "#1 The content before LaunchedEffect is: $content")
    
    LaunchedEffect(interactionSource) {
        Log.d("BUTTON", "#2 The content when LaunchedEffect starts is: ${latestContent.value}")
        interactionSource.interactions.onEach {
            when (it) {
                is PressInteraction.Press -> {
                    timeOfTouch = System.currentTimeMillis()
                    Log.d("BUTTON", "#3 The content after button pressed is: ${latestContent.value}")
                    Log.d("BUTTON", "the button has been pressed")
                }
                is PressInteraction.Release -> {
                    val currentTime = System.currentTimeMillis()
                    val calculatedPercentage: Float = defaultPercentage + 
                        ((currentTime - timeOfTouch).toFloat() / timeInMillis) * (1 - defaultPercentage)
                    // 使用latestContent.value传递最新值
                    onClick(min(calculatedPercentage, 1f), latestContent.value)
                    Log.d("BUTTON", "#4 The content after button is released is: ${latestContent.value}")
                    Log.d("BUTTON", "the button has been released, the calculated percentage is ${calculatedPercentage * 100}% and the duration is ${(currentTime - timeOfTouch)}ms")
                }
                is PressInteraction.Cancel -> {
                    timeOfTouch = -1L
                }
            }
        }.launchIn(this)
    }
    
    Modifier.clickable(
        interactionSource = interactionSource,
        indication = rememberRipple(),
        onClick = {}
    )
}
关键说明
  • rememberUpdatedState 会在 content 参数变化时自动更新其内部的 value,但不会触发LaunchedEffect重启,既保证能获取最新输入值,又不会中断用户正在进行的长按交互。
  • LaunchedEffect内部所有需要使用 content 的地方,都替换为 latestContent.value,确保拿到实时的TextField输入值。

内容的提问来源于stack exchange,提问作者Justice Gabriel Antaputra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:40:59