【问题标题】:Why does mutableStateOf without remember work sometimes?为什么没有记忆的 mutableStateOf 有时会起作用?
【发布时间】:2022-02-09 18:58:36
【问题描述】:

我一直在玩 Jetpack Compose Desktop。我注意到了一些我真的不明白的地方:

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application

@Composable
@Preview
fun App() {
    var text by mutableStateOf("Hello, World!")

    MaterialTheme {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

为什么我可以更改 TextField 中的文本?我想,在每次重组时,可变状态都会用初始值重新实例化:所以文本应该不能改变

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application

@Composable
@Preview
fun App() {
    var text by mutableStateOf("Hello, World!")

    Column {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

但是,如果您将 MaterialTheme 替换为 Column,它会突然按预期工作,并且您无法更改 TextField 中的文本。

这是为什么呢?这是错误还是功能?

【问题讨论】:

    标签: kotlin android-jetpack-compose


    【解决方案1】:

    这是 Compose 的一个关于范围界定和智能重组的功能。你可以查看我的详细回答here

    真正让您的整个 Composable 重构的是 Column 具有 inline 关键字。

    @Composable
    inline fun Column(
        modifier: Modifier = Modifier,
        verticalArrangement: Arrangement.Vertical = Arrangement.Top,
        horizontalAlignment: Alignment.Horizontal = Alignment.Start,
        content: @Composable ColumnScope.() -> Unit
    ) {
        val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
        Layout(
            content = { ColumnScopeInstance.content() },
            measurePolicy = measurePolicy,
            modifier = modifier
        )
    }
    

    假设您有一个 Composable 在合成时设置背景颜色,并在每次重新合成时更改,从而创建自己的范围。没有内联的 Lambda 被认为是一个作用域。

    @Composable
    fun RandomColorColumn(content: @Composable () -> Unit) {
    
        Column(
            modifier = Modifier
                .padding(4.dp)
                .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
                .background(getRandomColor())
                .padding(4.dp)
        ) {
            content()
        }
    }
    

    @Composable
    fun App2() {
        var text by mutableStateOf("Hello, World!")
    
        RandomColorColumn {
            TextField(text, onValueChange = { text = it })
            Button(onClick = {
                text = "Hello, Desktop!"
            }) {
                Text(text)
            }
        }
    }
    

    还有一个Column

    @Composable
    fun App() {
        var text by mutableStateOf("Hello, World!")
    
        Column(modifier = Modifier.background(getRandomColor())) {
            TextField(text, onValueChange = { text = it })
            Button(onClick = {
                text = "Hello, Desktop!"
            }) {
                Text(text)
            }
        }
    }
    

    随机颜色函数

    fun getRandomColor() =  Color(
        red = Random.nextInt(256),
        green = Random.nextInt(256),
        blue = Random.nextInt(256),
        alpha = 255
    )
    

    您会看到每次更改文本时列背景颜色都会发生变化,但App2()不会发生变化

    【讨论】:

      【解决方案2】:

      我认为,在每次重组时,可变状态都会用初始值重新实例化:所以文本不应该能够改变

      重组时有状态的目的是防止变量被重新初始化。初始状态仅在第一次合成发生时使用一次,并且在进一步重新合成发生时不再使用。但是,如果可组合对象从 UI 树中删除,然后稍后恢复,则变量的状态将被销毁并重新初始化,因为这不是真正的重新组合,而是组合(就好像它是第一次发生一样)。

      【讨论】:

      • 是的,我知道这一点,但为什么它会起作用
      猜你喜欢
      • 2011-02-03
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 2023-04-01
      • 2015-08-08
      • 1970-01-01
      相关资源
      最近更新 更多