Jetpack Compose:让用户编辑 StateFlow 对象中包含的文本值的正确方法

问题描述 投票:0回答:1

我有一个 ViewModel,其中包含一个名为

uiState
的 MutableStateFlow。

uiState 包含一个名为

myString
的字符串值,该值最初是从存储库(远程 API)初始化的,但随后应该可由用户编辑。每当用户编辑它时,都应该将其保存回存储库。

class MyViewModel {
    private val _uiState = MutableStateFlow(MyUiState())
    val uiState: StateFlow<MyUiState> = _uiState.asStateFlow()
}

我的理解是,您不应该将 StateFlow 值

uiState.myString
直接连接到 OutlinedTextField。例如,在此博客文章中明确说明了这一点:https://medium.com/androiddevelopers/ effective-state-management-for-textfield-in-compose-d6e5b070fbe5

那么实现所需行为的正确方法是什么?

这是我目前的想法,但我不知道这是否是个好主意:

在 Compose 函数中,定义一个本地字符串变量,最初由

uiState.myString
的值初始化,然后,当输入完成后,首先更新存储库,然后更新
uiState.myString


@Composable
fun MyTextEdit(
    initialValue: String // this arguments gets passed `uiState.myString` when
    onKeyboardDone: () -> Unit,
) {
    val editString: String = remember { mutableStateOf(default= initialValue) }
    OutlinedTextField(
    value = editString,
    onValueChange = { newValue => editString = newValue} 
    keyboardActions = KeyboardActions(
                    onDone = { saveToRegistryAndThenUpdateMyStringInUiState() }
    )

[...]
// And then the composable is called like this:

@Composable
fun MyUi(
    val uiState by MyViewModel.uiState.collectAsState()
    MyTextEdit(
        initialValue=uiState.myString,
        onKeyboardDone = { newValue ->
              saveToRepository(newValue){ 
                    savedValue -> uiState.update {
                        currentState ->
                        currentState.copy(myString = newValue)
                    }
              }
         }
)

这行得通吗?这是最好的解决方案吗?

android-jetpack-compose android-jetpack android-jetpack-compose-material3 jetpack
1个回答
0
投票

每当用户输入值时,最好在存储库中的某个时间戳之后保存

newValue
,而不是依赖键盘的
onDone
操作。

对于

delay
- 您可以使用
debounce

这是基本示例:

ViewModel
const val DEBOUNCE_DELAY = 600L

val newValue = MutableStateFlow("")

init {
    // This will be called at delay of 600MS whenever `newValue` is updated
    viewModelScope.launch {
        newValue.debounce {
            if (it.isEmpty()) 0 else DEBOUNCE_DELAY
        }.flowOn(appDispatcher.IO)
            .collectLatest { newStr ->
                if (newStr.isNotEmpty()) {
                    withContext(Dispatcher.IO) {
                            // Save newValue to repository & state
                         }
                    }
                }
            }
    }
}


fun onValueChange(newStr: String) {
    newValue.value = newStr
}

In View
@Composable
fun MyTextEdit(
    initialValue: String // this arguments gets passed `uiState.myString` when
    onKeyboardDone: () -> Unit,
) {
    val editString: String = remember { mutableStateOf(default= initialValue) }
    OutlinedTextField(
        value = editString,
        onValueChange = { newValue => MyViewModel.onValueChanged(newValue) } 
    )

[...]
© www.soinside.com 2019 - 2024. All rights reserved.