1

假设我们有一个 viewModel,里面有一个名为 apiKey 的值。此值的内容以 Flow 的形式从 DataStore 接收,然后作为 LiveData 公开。另一方面,我们有一个名为 SettingsFragment 的 Fragment,我们试图在 TextField 中显示该 apiKey,让用户对其进行修改并立即将其保存在 DataStore 中。我目前使用的解决方案在下面,但问题是当对文本进行更改时 UI 变得非常滞后和缓慢。我的问题是,实现这一点的最佳方法是什么,并且我们的 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)
            })
    }
}
4

1 回答 1

1

不要在每次按键时将 onValueChange 事件中的 TextField 值保存到数据存储中 - 这几乎肯定会减慢您的速度 - 特别是如果您使用相同的线程。使用本地状态变量,并且仅当用户将焦点移至其他位置或通过按下某些按钮保存屏幕上的内容时才更新数据存储。您还需要避免将 UI 线程与应该在 IO 线程上的数据存储线程混合。这是一种可能的解决方案:

@Composable
fun ContentViewHandler() {
    ContentView(
        initialText = viewmodel.getApiKey(),
        onTextChange = { text ->
            viewmodel.updateApiKey(text)
        }
    )
}

@Composable
fun ContentView(
    initialText: String,
    onTextChange: (text: String) -> Unit
) {
    var text by remember { mutableStateOf(initialText) }

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

        // Or add a button and save the text when clicked.
    }
}
于 2021-12-02T19:01:09.997 回答