nba*_*man 8 android state kotlin android-jetpack android-jetpack-compose
下面的两个示例简单地将“a”添加到给定的默认值。该compose_version
使用的1.0.0-alpha03
是最新的截至今天(据我所知)。
这个例子与我在研究过程中发现的大多数例子最相似。
示例 1
@Composable
fun MyScreen() {
val (name, setName) = remember { mutableStateOf("Ma") }
Column {
Text(text = name) // 'Ma'
Button(onClick = {
setName(name + "a") // change it to 'Maa'
}) {
Text(text = "Add an 'a'")
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这并不总是实用的。例如,数据比单个字段更复杂。例如一个类,甚至一个Room
data class
.
示例 2
// the class to be modified
class MyThing(var name: String = "Ma");
@Composable
fun MyScreen() {
val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) }
Column {
Text(text = myThing.name) // 'Ma'
Button(onClick = {
var nextMyThing = myThing
nextMyThing.name += "a" // change it to 'Maa'
setMyThing(nextMyThing)
}) {
Text(text = "Add an 'a'")
}
}
}
Run Code Online (Sandbox Code Playgroud)
当然,示例 1有效,但示例 2无效。这是我的一个简单错误,还是我错过了关于我应该如何修改这个类实例的大图?
编辑:
我有点找到了一种方法,使这项工作,但似乎效率不高。然而,它确实与 React 管理状态的方式一致,所以也许这是正确的方法。
示例 2 中的问题很明显myNextThing
不是原始 的副本myThing
,而是对它的引用。就像 React 一样,Jetpack Compose 在修改状态时似乎想要一个全新的对象。这可以通过以下两种方式之一完成:
MyThing
,更改需要更改的内容,然后setMyThing()
使用新的类实例进行调用class MyThing
到data class MyThing
和使用copy()
功能来创建具有相同属性的新实例。然后,更改所需的属性并调用setMyThing()
。鉴于我明确表示我想用它来修改data class
Android Room 使用的给定数据,这是我问题上下文中的最佳方法。示例 3 (功能)
// the class to be modified
data class MyThing(var name: String = "Ma");
@Composable
fun MyScreen() {
val (myThing, setMyThing) = remember { mutableStateOf(MyThing()) }
Column {
Text(text = myThing.name) // 'Ma'
Button(onClick = {
var nextMyThing = myThing.copy() // make a copy instead of a reference
nextMyThing.name += "a" // change it to 'Maa'
setMyThing(nextMyThing)
}) {
Text(text = "Add an 'a'")
}
}
}
Run Code Online (Sandbox Code Playgroud)
Aug*_*nso 12
好吧,对于任何想知道这个问题的人来说,有一个更简单的方法来解决这个问题。当您像这样定义可变状态属性时:
//There is a second paremeter wich defines the policy of the changes on de state if you
//set this value to neverEqualPolicy() you can make changes and then just set the value
class Vm : ViewModel() {
val dummy = mutableStateOf(value = Dummy(), policy= neverEqualPolicy())
//Update the value like this
fun update(){
dummy.value.property = "New value"
//Here is the key since it has the never equal policy it will treat them as different no matter the changes
dummy.value = dummy.value
}
}
Run Code Online (Sandbox Code Playgroud)
有关可用策略的更多信息: https://developer.android.com/reference/kotlin/androidx/compose/runtime/SnapshotMutationPolicy
Com*_*are 11
事实上,在我看来,解决此问题的最佳方法是 copy() 数据类。
remember()
在使用custom 的特定情况下data class
,这可能确实是最好的选择,尽管可以通过在函数上使用命名参数来更简洁地完成copy()
:
// the class to be modified
data class MyThing(var name: String = "Ma", var age: Int = 0)
@Composable
fun MyScreen() {
val (myThing, myThingSetter) = remember { mutableStateOf(MyThing()) }
Column {
Text(text = myThing.name)
// button to add "a" to the end of the name
Button(onClick = { myThingSetter(myThing.copy(name = myThing.name + "a")) }) {
Text(text = "Add an 'a'")
}
// button to increment the new "age" field by 1
Button(onClick = { myThingSetter(myThing.copy(age = myThing.age + 1)) }) {
Text(text = "Increment age")
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我们仍将更新视图模型并观察它们的结果(LiveData
、StateFlow
、 RxJavaObservable
等)。我希望它将remember { mutableStateOf() }
在本地用于尚未准备好提交到视图模型但需要多位用户输入的数据,因此需要表示为状态。您是否觉得需data class
要这样做取决于您。
这对我来说是一个简单的错误,还是我错过了关于如何修改此类实例的更大的图景?
Compose 无法知道对象发生了变化,因此它不知道需要重新组合。
总的来说,Compose 是围绕对不可变数据流做出反应而设计的。remember { mutableStateOf() }
创建本地流。
然而,另一种方法将受到欢迎。
您不限于单一remember
:
@Composable
fun MyScreen() {
val name = remember { mutableStateOf("Ma") }
val age = remember { mutableStateOf(0) }
Column {
Text(text = name.value)
// button to add "a" to the end of the name
Button(onClick = { name.value = name.value + "a"}) {
Text(text = "Add an 'a'")
}
// button to increment the new "age" field by 1
Button(onClick = { age.value = age.value + 1 }) {
Text(text = "Increment age")
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1746 次 |
最近记录: |