Android StateFlow 集合覆盖 UI 更改
Android StateFlow collection overrides UI changes
假设有一个带有 Switch
和 EditText
控件的 FilterActivity。后者已禁用输入但可点击。单击它会启动 TypeActivity 以从中选择一个类型值,然后将类型名称填充到 EditText 中。
有一个 StateFlow<FilterUiState>
的 FilterViewModel
data class FilterUiState(
var status: Boolean = false,
var type: String = "sometype"
)
在onCreate中由activity这样收集
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
binding.run {
statusSwitch.isChecked = it.status
typeEditText.text = it.type
}
}
}
}
问题是,如果用户更改 statusSwitch 状态,然后单击 typeEditText 来选择一个类型,然后在 return 后恢复 FilterActivity,这会触发 uiState.collect 并因此重置statusSwitch 检查状态回到初始值。
防止 UI 更改被 StateFlow 收集覆盖的正确方法是什么?
您需要使用您希望它保持的最新状态实际更新状态流,然后它会在收集时正确恢复最新状态。
此外,不要为此使用可变 class。将可变 classes 与 StateFlows 混合使用很容易出错。如果您改变它已经持有的实例,StateFlow 无法检测到发生了变化。
data class FilterUiState(
val status: Boolean = false,
val type: String = "sometype"
)
// in ViewModel class:
private val mutableUiState = with(PreferenceManager.getDefaultSharedPreferences(context)) {
val status = //...get these from shared preferences
val type = //...
val initialState = FilterUiState(status, type)
MutableStateFlow(initialState)
}
val uiState = mutableUiState.asStateFlow()
fun updateStatus(status: Boolean) {
mutableUiState.value = mutableUiState.value.copy(status = status)
// and update the SharedPreferences value
}
fun updateType(type: String) {
mutableUiState.value = mutableUiState.value.copy(type = type)
// and update the SharedPreferences value
}
并在这些值发生变化时从 Activity 调用这两个 update
函数。您可以向复选框添加一个点击侦听器,以针对“状态”和 EditText 执行此操作,因为您已禁用输入,所以您可以调用 updateType()
函数,而不是在从另一个返回时直接修改其文本 Activity。当您更新视图模型中的状态时,您现有的收集器会为您更新小部件中的文本。
假设有一个带有 Switch
和 EditText
控件的 FilterActivity。后者已禁用输入但可点击。单击它会启动 TypeActivity 以从中选择一个类型值,然后将类型名称填充到 EditText 中。
有一个 StateFlow<FilterUiState>
data class FilterUiState(
var status: Boolean = false,
var type: String = "sometype"
)
在onCreate中由activity这样收集
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
binding.run {
statusSwitch.isChecked = it.status
typeEditText.text = it.type
}
}
}
}
问题是,如果用户更改 statusSwitch 状态,然后单击 typeEditText 来选择一个类型,然后在 return 后恢复 FilterActivity,这会触发 uiState.collect 并因此重置statusSwitch 检查状态回到初始值。
防止 UI 更改被 StateFlow 收集覆盖的正确方法是什么?
您需要使用您希望它保持的最新状态实际更新状态流,然后它会在收集时正确恢复最新状态。
此外,不要为此使用可变 class。将可变 classes 与 StateFlows 混合使用很容易出错。如果您改变它已经持有的实例,StateFlow 无法检测到发生了变化。
data class FilterUiState(
val status: Boolean = false,
val type: String = "sometype"
)
// in ViewModel class:
private val mutableUiState = with(PreferenceManager.getDefaultSharedPreferences(context)) {
val status = //...get these from shared preferences
val type = //...
val initialState = FilterUiState(status, type)
MutableStateFlow(initialState)
}
val uiState = mutableUiState.asStateFlow()
fun updateStatus(status: Boolean) {
mutableUiState.value = mutableUiState.value.copy(status = status)
// and update the SharedPreferences value
}
fun updateType(type: String) {
mutableUiState.value = mutableUiState.value.copy(type = type)
// and update the SharedPreferences value
}
并在这些值发生变化时从 Activity 调用这两个 update
函数。您可以向复选框添加一个点击侦听器,以针对“状态”和 EditText 执行此操作,因为您已禁用输入,所以您可以调用 updateType()
函数,而不是在从另一个返回时直接修改其文本 Activity。当您更新视图模型中的状态时,您现有的收集器会为您更新小部件中的文本。