我使用Textfield来获取用户输入,并使用stateflow来处理视图模型中的文本状态/值.

事情是每次文本字段值改变时,HomeContent()函数都会被重组. Layout inspector output image个 我的问题是整个HomeContent()函数正在被重新组合吗 仅仅因为文本字段值的改变或它们是避免函数重组的一种方法.

视图模型

class My视图模型() : 视图模型() {
    private val _nameFlow = MutableStateFlow("")
    val nameFlow = _nameFlow.asStateFlow()

    fun updateName(name: String) {
        _nameFlow.value = name
    }
}

主活性

class 主活性 : ComponentActivity() {
    private val my视图模型 by viewModels<My视图模型>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppArchitectureTheme {
                HelloScreen(my视图模型)
            }
        }
    }
}

主屏幕

@Composable
fun HelloScreen(viewModel: My视图模型) {
    val name = viewModel.nameFlow.collectAsState()
    HelloContent(
        provideName = { name.value },
        onNameChange = { viewModel.updateName(it) })
}

@Composable
fun HelloContent(
    provideName: () -> String,
    onNameChange: (String) -> Unit
) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello,",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.h5
        )
        OutlinedTextField(
            value = provideName(),
            onValueChange = { onNameChange(it) },
            label = { Text("Name") }
        )
        Button(
            onClick = {}
        ) {
            Text(text = "Dummy Button")
        }
    }
}

推荐答案

这确实是意料之中的行为.合成仅重组最近的作用域.作用域是返回Unit的非内联可组合函数.

你可以在下面的链接中阅读关于这个问题的答案.然而,链接中的问题和答案之间的差异也是defer reading change,这使得当lambda中的值发生变化时,不会重新组合其中的可组合元素.

Jetpack Compose Smart Recomposition

Why does mutableStateOf without remember work sometimes?

How can I launch recomposition when a specified Flow changed in Jetpack Compose?

如果将OutlinedTextField更改为

@Composable
private fun MyOutlinedTextField(
    provideName: () -> String,
    onNameChange: (String) -> Unit
) {
    OutlinedTextField(
        value = provideName(),
        onValueChange = { onNameChange(it) },
        label = { Text("Name") }
    )
}

仅当该函数读取的参数更改时,才会重新组合该函数.如果有多个MyOutlinedTextField,则只会更改读取相应值的那个.

然而,这与我提供的链接中的答案之间有一个微妙且非常重要的区别,那就是通过传递来推迟状态读取

provideName: () -> String个而不是provideName: String

这将从派生的Composable中延迟状态读取,以仅读取该lambda的状态.这就是如何仅在MyOutlinedTextField个作用域内触发重组.

如果您按如下方式更新您的函数,您将看到它将再次重新组成整个HelloContent作用域,包括这里Column内的Text

@Composable
fun HelloContent(
    provideName: String,
    onNameChange: (String) -> Unit
) {
    Column(
        modifier = Modifier
            .background(getRandomColor())
            .padding(16.dp)
    ) {

        Column( Modifier
            .background(getRandomColor())) {
            Text(
                text = "Hello,",
                modifier = Modifier.padding(bottom = 8.dp),
            )
        }

        MyOutlinedTextField(provideName = provideName, onNameChange = onNameChange)

        Button(
            onClick = {}
        ) {
            Text(
                text = "Dummy Button", modifier = Modifier
                    .background(getRandomColor())
            )
        }
    }
}

该函数重组随机 colored颜色 函数所在的Column

fun getRandomColor(): Color {
    return Color(
        Random.nextInt(256),
        Random.nextInt(256),
        Random.nextInt(256),
        255
    )
}

此外,这也是我准备的教程,其中包括作用域重组和延迟阅读.您可以查看此示例以了解读取偏移量和填充更改.

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter4_state/Tutorial4_7_3ComposePhases3.kt

enter image description here

Android相关问答推荐

RemoteActivityHelper.startRemoteActivity不适用于Android Wear OS 4模拟器

不能在LazyGrid-Jetpack Compose中使用填充最大宽度或填充父项最大宽度

在Jetpack Compose中,如何判断屏幕是否已重新组合?

Kotlin Android VS Kotlin多平台

在Jetpack Compose中,我可以配置动画以恒定的速度而不是恒定的时间运行吗?

SDK 33 的问题 - 面向 S+(版本 31 及更高版本)要求在创建 PendingIntent 时指定 FLAG_IMMUTABLE 或 FLAG_MUTABLE 之一

如何将 Room Persistence 依赖项正确添加到我的 Jetack Compose Android 应用程序

Android kotlin 中闪屏 API 执行完成后如何根据身份验证将用户导航到特定屏幕

如何将DrawableId参数传递给XML布局?

Android Jetpack Compose全宽度抽屉优化

如何仅使用您的 Android 应用程序定位平板电脑?

Android AGP 8 + Gradle 8 + Kotlin 1.8 导致 Kapt 出错

单击按钮时不显示 Toast 消息

我怎样才能在多行 TextView 旁边有一个 ImageView 并且不超过父级的限制?

将 CircularProgressIndicator 添加到按钮而不增加其高度

Jetpack 组合千位分隔符视觉转换,也适用于小数

如何在 Android Studio 中创建新的可组合函数?

单击登录按钮后从应用程序中退出

Android - 水平(从右到左)圆形背景 colored颜色 过渡

Android Studio (Kotlin):无法启动活动