Android Jetpack Compose - 每次文本字段值更改时都会重新组合可组合函数

Har*_*rsh 6 android android-jetpack-compose android-compose-textfield

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

问题是每次TextField的值发生变化时,HomeContent()函数都会被重新组合。
布局检查器输出图像 我的问题是,仅仅HomeContent()因为值发生变化就可以重构整个函数TextField,还是有办法避免函数重构?

视图模型

class MyViewModel() : ViewModel() {
    private val _nameFlow = MutableStateFlow("")
    val nameFlow = _nameFlow.asStateFlow()

    fun updateName(name: String) {
        _nameFlow.value = name
    }
}
Run Code Online (Sandbox Code Playgroud)

主要活动

class MainActivity : ComponentActivity() {
    private val myViewModel by viewModels<MyViewModel>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppArchitectureTheme {
                HelloScreen(myViewModel)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

主屏幕

@Composable
fun HelloScreen(viewModel: MyViewModel) {
    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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Thr*_*ian 13

这确实是预期的行为。Compose 仅​​重构“最近”的范围。作用域是返回 的非内联可组合函数Unit

您可以在下面的链接中阅读有关此问题的答案。然而,链接中问题和答案之间的区别在于,您还推迟了阅读更改,这使得当 lambda 内的值发生变化时,可组合项不会被重新组合。

Jetpack Compose 智能重组

为什么有时没有记住的 mutableStateOf 也能工作?

当 Jetpack Compose 中的指定流程发生更改时,如何启动重组?

如果你更改OutlinedTextField

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

只有当它读取的参数发生变化时,这个函数才会被重构。如果有多个MyOutlinedTextField,则只有读取相应值的那个会发生变化。

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

provideName: () -> String代替provideName: String

这会将状态读取从后代可组合项推迟到仅读取此 lambda 的可组合项。这就是仅针对范围触发重组的方式MyOutlinedTextField

如果您按如下方式更新函数,您将看到它将再次重组整个HelloContent范围,包括此处Text的内部Column

@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())
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该函数重构了Column随机颜色函数的位置

fun getRandomColor(): Color {
    return Color(
        Random.nextInt(256),
        Random.nextInt(256),
        Random.nextInt(256),
        255
    )
}
Run Code Online (Sandbox Code Playgroud)

另外,这是我准备的教程,其中涵盖范围重组和延迟读取。您可以查看此示例以了解读取偏移量和填充更改。

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

在此输入图像描述