我有一个 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)
}
}
}
)
这行得通吗?这是最好的解决方案吗?
每当用户输入值时,最好在存储库中的某个时间戳之后保存
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) }
)
[...]