我有一个片段,它从视图模型状态流收集后显示一个位置,该位置存储在共享首选项中,而不是在片段启动时发送到可变流状态。
该片段可以显示 BottomSheetDialogue,在 BottomSheetDialog 中用户可以更新位置,我通过共享首选项和可变状态流中的视图模型更新位置。
问题是当更新新位置并且关闭底部工作表时,新值不会收集在片段中,或者不会通知收集器。
我不确定我到底做错了什么。
碎片
val viewModel: LocationViewModel by viewModels() lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.shippingLocation.collect { location ->
if (location != null) {
binding.shippingLocation.text = location
} else {
binding.shippingLocation.text = ""
}
}
}
}
binding.shippingLocationEditBtn.setOnClickListener {
val editLocationSheet = EditLocationFragment()
editLocationSheet.show(parentFragmentManager, "EditLocationSheet")
}
视图模型
private val _shippingLocation = MutableStateFlow<String?>(null)
val shippingLocation: StateFlow<String?> = _shippingLocation.asStateFlow()
init {
getShippingLocation()
}
fun updateShippingLocation(location: String?) {
sharedPreferences.edit()
.putString(PREFS_SHIPPING_LOCATION_KEY, location)
.apply()
_shippingLocationWilaya.value = location
}
private fun getShippingLocation() {
val location = sharedPreferences.getString(PREFS_SHIPPING_LOCATION_KEY, null)
viewModelScope.launch {
if (location == null) {
_shippingLocation.value = ""
} else {
_shippingLocation.value = location
}
}
}
BottomSheetDialog
val viewModel: LicationViewModel by viewModels()
binding.editShippingLocationTopAppBar.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.saveShippingLocation -> {
if (location != null) {
viewModel.updateShippingLocation(location)
dismiss()
} else {
Toast.makeText(
requireContext(),
"Please select a location",
Toast.LENGTH_SHORT
).show()
}
true
}
else -> false
}
}
您仅在视图启动状态下收集值,这意味着仅当视图启动时才会收集该值,而不是每次更改其值时。
每次变化都需要收集该值。
val viewModel: LocationViewModel by viewModels()
lifecycleScope.launch {
viewModel.shippingLocation.collect { location ->
binding.shippingLocation.text = location.orEmpty()
}
}
binding.shippingLocationEditBtn.setOnClickListener {
val editLocationSheet = EditLocationFragment()
editLocationSheet.show(parentFragmentManager, "EditLocationSheet")
}
我发现问题是我没有相同的视图模型实例,在每个片段中创建了一个新的视图模型实例(带有新数据)。
我认为
viewModels()
函数与 hilt
(视图模型级别的 @HiltViewModel
表示法)一起使用来创建跨片段的 shared viewmodel
,但事实证明我对此是错误的。
这是你的问题;
init { getShippingLocation() }
这部分不起作用。
也许,您可以将 Dispatcher 添加到您的 getShippingLocation 函数中, 如果可以的话,您可以尝试执行公共功能并删除 init 块。