Kotlin Stateflow 新值发出但未收集

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

我有一个片段,它从视图模型状态流收集后显示一个位置,该位置存储在共享首选项中,而不是在片段启动时发送到可变流状态。

该片段可以显示 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
            }
        }
android android-fragments android-viewmodel kotlin-stateflow
3个回答
0
投票

您仅在视图启动状态下收集值,这意味着仅当视图启动时才会收集该值,而不是每次更改其值时。

每次变化都需要收集该值。

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")
}

0
投票

我发现问题是我没有相同的视图模型实例,在每个片段中创建了一个新的视图模型实例(带有新数据)。

我认为

viewModels()
函数与
hilt
(视图模型级别的
@HiltViewModel
表示法
)一起使用来创建跨片段的
shared viewmodel
,但事实证明我对此是错误的。


0
投票

这是你的问题;

 init { getShippingLocation() }

这部分不起作用。

也许,您可以将 Dispatcher 添加到您的 getShippingLocation 函数中, 如果可以的话,您可以尝试执行公共功能并删除 init 块。

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