简体   繁体   English

Jetpack Compose:mutableStateOf 不随流量更新

[英]Jetpack Compose: mutableStateOf doesn't update with flow

I have a ViewModel which uses Flow to get a Note object from my Room database:我有一个 ViewModel,它使用 Flow 从我的 Room 数据库中获取 Note object:

var uiState by mutableStateOf(NoteUiState())
        private set


    private fun getNoteById(argument: Int) {
        viewModelScope.launch {
            try {
                repository.getNoteById(argument).collect { note ->
                    uiState = NoteUiState(note = note)
                }
            } catch (e: Exception) {
                uiState = NoteUiState(error = true)
            }
        }
    }

Note class:注意 class:

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "title") val title: String = "",
    @ColumnInfo(name = "text") val text: String = "",
) {
    override fun toString() = title
}

This approach works fine, until I try to make a mutable strings with the values of the Note object as their default so I can update 2 TextField composables:这种方法效果很好,直到我尝试使用 Note object 的值作为默认值创建一个可变字符串,以便我可以更新 2 个 TextField 可组合项:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Note(
    note: DataNote,
    isNewNote: Boolean,
    createNote: (DataNote) -> Unit,
    updateNote: (DataNote) -> Unit,
    back: () -> Unit,
    trued: String,
) {

    var title by remember { mutableStateOf(note.title) }
    var content by remember { mutableStateOf(note.text) }
    TextField(
        value = title,
        onValueChange = { title = it },
        modifier = Modifier
            .fillMaxWidth(),
        placeholder = { Text(text = "Title") },
        colors = TextFieldDefaults.textFieldColors(
            containerColor = Color.Transparent
        )
    )
    TextField(
        value = content,
        onValueChange = { content = it },
        modifier = Modifier
            .fillMaxWidth(),
        placeholder = { Text(text = "Content") },
        colors = TextFieldDefaults.textFieldColors(
            containerColor = Color.Transparent
        )
    )
}

For some reason the first time the Note object is called it's null, so I want a way to update the title and content variables.由于某种原因,Note object 第一次被称为 null,所以我想要一种更新标题和内容变量的方法。

The Note object itself updates without issue, however the title and content variables never change from the initial value. Note object 本身更新没有问题,但标题和内容变量从初始值不变。 How can I update the title and content variables while also making them work for the textfield?如何更新标题和内容变量,同时使它们适用于文本字段?

use SideEffect to update title and content使用 SideEffect 更新标题和内容

 var title by remember { mutableStateOf(note.title) }
    var content by remember { mutableStateOf(note.text) }

remember block executes only on 1st composition and then value will remembered until decomposition or u need to change it externally through '=' assignment operator,记住块仅在第一次组合时执行,然后值将被记住,直到分解或您需要通过“=”赋值运算符从外部更改它,

. .

instated of this对此作出规定

TextField(
        value = title)

write this way这样写

 TextField(
            value = note.title)

I found out how to make the Textfield work while also getting the inital value from the object.我发现了如何使 Textfield 工作,同时还从 object 获取初始值。 The issue was that the Note object was called as null on the first call, so the mutableStateFlow didnt get the initial values.问题是 Note object 在第一次调用时被称为 null,因此 mutableStateFlow 没有获得初始值。

First, I had to pass the actual state as a MutableStateFlow to my composable:首先,我必须将实际的 state 作为 MutableStateFlow 传递给我的可组合:

@Composable
private fun Note(
    state: MutableStateFlow<NoteUiState>,
    createNote: (DataNote) -> Unit,
    updateNote: (DataNote) -> Unit,
    back: () -> Unit
) {
...

Next, I just had to get the Note object by calling collectAsState() :接下来,我只需要通过调用collectAsState()来获取 Note object :

val currentNote = state.collectAsState().value.note

Finally, all that was needed was to pass the currentNote object text and title in the value of the Textfield, and on onValueChange to update the state object itself via a copy:最后,只需要在 Textfield 的值中传递 currentNote object 文本和标题,然后在onValueChange上通过副本更新 state object 本身:

This is the complete solution:这是完整的解决方案:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Note(
    state: MutableStateFlow<NoteUiState>,
    createNote: (DataNote) -> Unit,
    updateNote: (DataNote) -> Unit,
    back: () -> Unit
) {
    val currentNote = state.collectAsState().value.note
    Column(Modifier.fillMaxSize()) {
        TextField(
            value = currentNote.title,
            onValueChange = {
                state.value = state.value.copy(note = currentNote.copy(title = it))
                            },
            modifier = Modifier
                .fillMaxWidth(),
            placeholder = { Text(text = "Title") },
            colors = TextFieldDefaults.textFieldColors(
                containerColor = Color.Transparent
            )
        )
    }
}

I'm not sure is this is a clean solution, but is the only way it worked for me, thanks for the feedback, opinions on this approach are always welcomed.我不确定这是一个干净的解决方案,但它是唯一对我有用的方法,感谢您的反馈,总是欢迎对这种方法提出意见。

You should think about state hoisting and about having a single source of truth.您应该考虑state 提升以及拥有单一事实来源。

Really you need to define where your state will live, if on the viewmodel or on the composable functions.If you are only going to use the state (your note) on the ui then it's ok to hoist your state up to the Note composable function. Really you need to define where your state will live, if on the viewmodel or on the composable functions.If you are only going to use the state (your note) on the ui then it's ok to hoist your state up to the Note composable function .

But if you need that state in something like another repo, insert it somewhere else or in general to do operations with it, the probably you should hoist it up to the viewmodel (you already have it there).但是,如果您需要将 state 放在另一个仓库之类的东西中,请将其插入其他地方或通常对其进行操作,您可能应该将其提升到视图模型(您已经拥有它)。

So use the property of your viewmodel directly in your composable and add a function in your viewmodel to mutate the state and pass this function to the onValueChanged lambda . So use the property of your viewmodel directly in your composable and add a function in your viewmodel to mutate the state and pass this function to the onValueChanged lambda .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Jetpack compose 不会在 mutableStateOf 更改时重新组合 - Jetpack compose doesn't recompose on mutableStateOf change Jetpack Compose - mutableStateOf() 未更新 - Jetpack Compose - mutableStateOf() not updating @Model Jetpack Compose 不更新 UI - @Model Jetpack Compose doesn't update UI mutableStateOf 始终显示 0(Jetpack Compose with ViewModel) - mutableStateOf always displaying 0 (Jetpack Compose with ViewModel) 我不明白为什么当我将列表更改为 mutableStateOf 时 Jetpack Compose 不重新组合? - I don't understand why Jetpack Compose don't recompose when I change list into a mutableStateOf? MutableLiveData 观察方法运行但不更新 Jetpack Compose 列表 - MutableLiveData observe method runs but doesn't update Jetpack Compose list 变量不使用jetpack compose在可组合内部更新 - Variable doesn't update inside composable using jetpack compose jetpack compose 中的 MutableStateFlow("") 与 mutableStateOf("") 有什么区别? - what is thee difference between MutableStateFlow("") vs mutableStateOf("") in jetpack compose? 当我们在 Jetpack compose 中有 mutableStateOf 时调用两次权限 - Permission called twice when we have mutableStateOf in Jetpack compose onKeyEvent 修饰符在 Jetpack Compose 中不起作用 - onKeyEvent Modifier doesn't work in Jetpack Compose
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM