简体   繁体   English

使用 viewModel 作为 jetpack compose 中的单一事实来源

[英]Using viewModel as the single source of truth in jetpack compose

let's say we have a viewModel that has a value called apiKey inside.假设我们有一个 viewModel,里面有一个名为 apiKey 的值。 Contents of this value is received from DataStore in form of a Flow and then, it is exposed as LiveData.此值的内容以 Flow 的形式从 DataStore 接收,然后作为 LiveData 公开。 On the other hand we have a Fragment called SettingsFragment, and we are trying to display that apiKey inside a TextField, let the user modify it and save it in DataStore right away.另一方面,我们有一个名为 SettingsFragment 的 Fragment,我们试图在 TextField 中显示该 apiKey,让用户对其进行修改并立即将其保存在 DataStore 中。 The solution that I'm currently using is down below, but the issue is that the UI gets very laggy and slow when changes are being made to the text.我目前使用的解决方案在下面,但问题是当对文本进行更改时 UI 变得非常滞后和缓慢。 My question is that what is the best way to implement this and still have a single source of truth for our apiKey?我的问题是,实现这一点的最佳方法是什么,并且我们的 apiKey 仍然拥有单一的事实来源?

class SettingsViewModel() : ViewModel() {

    val apiKey = readOutFromDataStore.asLiveData()

    fun saveApiKey(apiKey: String) {
        viewModelScope.launch(Dispatchers.IO) {
            saveToDataStore("KEY", apiKey)
        }
    }
}

/** SettingsFragment **/
...

@Composable
fun ContentView() {
    var text = mViewModel.apiKey.observeAsState().value?.apiKey ?: ""

    Column() {
        OutlinedTextField(
            label = { Text(text = "API Key") },
            value = text,
            onValueChange = {
                text = it
                mViewModel.saveApiKey(it)
            })
    }
}

have you tried removing text = it from your textfield onValueChange ?您是否尝试过从文本字段onValueChange中删除text = it If you're observing the value form the viewModel it should change automatically如果您从 viewModel 观察值,它应该会自动更改

Don't save the TextField's value in the onValueChange event to the data store on every key press - which is almost certainly slowing you down - especially if you are using the same thread.不要在每次按键时将 onValueChange 事件中的 TextField 值保存到数据存储中 - 这几乎肯定会减慢您的速度 - 特别是如果您使用相同的线程。 Use a local state variable and only update the data store when the user either moves the focus elsewhere or they save what's on the screen through some button press.使用本地 state 变量,并且仅当用户将焦点移至其他位置或通过按下某些按钮保存屏幕上的内容时才更新数据存储。 You also need to avoid mixing UI threading with data storage threading which should be on the IO thread.您还需要避免将 UI 线程与应该在 IO 线程上的数据存储线程混合。 Here is one possible solution:这是一种可能的解决方案:

@Composable
fun ContentView() {
    var text by remember { mutableStateOf(mViewModel.apiKey ?: "")}

    Column() {
        OutlinedTextField(
            label = { Text(text = "API Key") },
            value = text,
            onValueChange = {
                text = it
            },
            modifier = Modifier.onFocusChanged { // Save text})
    }

    // Or add a button and save the text when clicked.
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM