在Android Jetpack Compose中,“remember”和“mutableState”的区别是什么?

85

我是Jetpack Compose的新手,想要了解remembermutableStateOf之间的区别。


换句话说,这行代码的区别:

val text = remember{ mutableStateOf("") }

还有这个

val text = remember{ "" }

并且这也

val text = mutableStateOf("")
6个回答

117

remember 是一个组合函数,可用于缓存昂贵的操作。您可以将其视为与您的组合函数本地的缓存。

val state: Int = remember { 1 }

上述代码中的state是不可变的。如果你想改变该状态并且更新UI,可以使用MutableStateCompose将观察任何读/写MutableState对象的操作,并触发重新组合(recomposition)以更新UI。

val state: MutableState<Int> = remember { mutableStateOf(1) }

Text(
   modifier = Modifier.clickable { state.value += 1 },
   text = "${state.value}",
 )

另一种变体(添加于 alpha12 版本)称为 rememberSaveable,类似于 remember,但存储的值可以在进程死亡或配置更改后继续存在。

val state: MutableState<Int> = rememberSaveable { mutableStateOf(1) }

注意:你也可以使用属性委托作为语法糖来解包 MutableState

var state: Int by remember { mutableStateOf(1) }

关于您问题的最后一部分:

val text = mutableStateOf("")
MutableState是使用LiveDataFlow的替代方法。默认情况下,Compose不会观察此对象的任何更改,因此不会进行重新组合。如果您想要观察更改并缓存状态,请使用remember。如果您不需要缓存但只想观察,则可以使用derivedStateOf。这里是如何使用它的示例

正如在评论中被Ahmad Hamwi指出并引用他们所说的:

实际上,Compose确实观察状态的值,在其顶部有一个@Stable注释,那就是它的唯一责任,但由于我们没有记住状态,mutableStateOf(1)将总是被再次创建,因此将存在一个新的状态实例,但仍将具有相同的值为1。因此,状态似乎没有变化,但确实发生了重新组合。


您可以检查一下问题的编辑吗?@ckunder - Ahmed Abdalla
@AhmedM.Abdalla 我已经更新了我的回答。 - ckunder
1
@ckunder 在你的回答的最后一部分引用了你的话:“Compose默认不会观察此对象的任何更改,因此不会发生重新组合”。实际上,Compose确实观察状态的值,在其顶部有一个@Stable注释,这是它唯一的责任,但由于我们没有记住状态,所以mutableStateOf(1)将始终被创建,因此将有一个新的状态实例,但仍将具有相同的值1。因此,状态似乎没有改变,但确实发生了重新组合。 - Ahmad Hamwi
记住与观察数据无关。 - Waldmann
所以...也许是一个愚蠢的问题,但mutableStateOf有什么意义呢?似乎每次使用它时我们都会与remember配对使用。我为什么要单独使用它呢? - Fred

20

据我理解。

记住只需将计算结果缓存以在组合之间保持结果实例。任何对象。以及MutableState实例。这就是它有用的原因。

val text = remember{ "" }

仅缓存空字符串。

val text = mutableStateOf("")

创建MutableState并使用compose观察它的值,但不要缓存MutableState实例,这样它将在下一次重新组合时重新创建(当然,如果重新组合在此处发生)

例如:

val state: MutableState<Int> =  mutableStateOf(1)
println(state.toString())
Text(
    modifier = Modifier.clickable { state.value += 1 },
    text = "${state.value}",
)

文本始终为1,因为每次重新构建都会重新创建state,输出将是:

MutableState(value=1)@227069120
MutableState(value=1)@104526071
MutableState(value=1)@915621104
MutableState(value=1)@580489706 

remember 缓存 MutableState 对象,并在每次重新组合时保持相同的实例。

val state: MutableState<Int> = remember { mutableStateOf(1) }
println(state.toString())
Text(
    modifier = Modifier.clickable { state.value += 1 },
    text = "${state.value}",
)

正常工作。

MutableState(value=2)@1121832406
MutableState(value=3)@1121832406
MutableState(value=4)@1121832406
MutableState(value=5)@1121832406

remember(key)

val key = remember { 0 }
var state by remember(key) { mutableStateOf(1) }
println(state.toString())
Text(
    modifier = Modifier.clickable { state += 1 },
    text = "${state}",
)

即使像上面的示例一样,key 没有改变,也可以正常工作。这是因为在 MutableState 的情况下,缓存的不是值,而是带有 value 字段且会改变的 MutableState 实例本身。

更改 key 值将重新创建 MutableState 实例。


2
这个答案给出了根本原因:当函数被重复调用时,保留状态数据,否则它将被重复初始化。 - hyyou2010

12
如果使用 remember 来定义一个变量,那么这个变量的值在组件重新渲染时会被保留。
如果使用 mutableState 来定义一个变量,那么当这个变量的值改变时,所有引用了这个变量的组件都会被重新渲染。

4

mutableStateOf(): 这是一种可观察的对象,当底层值发生更改并更新UI时进行观察。就像我们使用LiveDataStateFlows一样,但LiveData也具有生命周期机制,并且与StateFlows几乎相同。

remember{}: 它可以跨重新组合保持数据。
什么是重新组合?当状态发生更改时,持有该值的可组合项将重新组合自身,以给出更新的值。
例如: 我们有一个textView(可组合项)来观察值,现在它是1。我们按下按钮并将值增加2。当值从1变为2时,textView(可组合项)会重新创建(重新组合)自身并显示更新后的值,即2,这称为重新组合。


当我们使用此代码:val text = remember{ mutableStateOf("") },这意味着我们不仅正在观察数据,还在跨重新组合中保留数据。


2
基本上,在第一个示例中,您正在存储可变值,在第二个示例中,您正在存储不可变值。
根据文档:“当缓存昂贵的 UI 操作(例如计算文本格式)时,可以存储不可变值。记住的值存储在与调用 remember 的可组合项一起的 Composition 中。”来源 有关 mutableStateOf 的更多信息,请参阅此文档链接。当您的值发生更改时,您使用它来重新组成您的 UI。

2

remember关键字可以存储可变或不可变对象。如果您将mutableStateOf传递给remember,则每当该对象的值更改时,它都会强制重新组合正在读取该值的组合内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接