![](/img/trans.png)
[英]ViewModel onchange gets called multiple times when back from Fragment
[英]Kotlin ViewModel onchange gets called multiple times when back from Fragment (using Lifecycle implementation)
我正在使用 MVVM 架構。
當我單擊一個按鈕時,會觸發orderAction方法。 它只是發布一個枚舉(將添加進一步的邏輯)。
視圖模型
class DashboardUserViewModel(application: Application) : SessionViewModel(application) {
enum class Action {
QRCODE,
ORDER,
TOILETTE
}
val action: LiveData<Action>
get() = mutableAction
private val mutableAction = MutableLiveData<Action>()
init {
}
fun orderAction() {
viewModelScope.launch(Dispatchers.IO) {
// Some queries before the postValue
mutableAction.postValue(Action.QRCODE)
}
}
}
片段觀察 LiveData obj 並調用打開新片段的方法。 我在這里使用導航器,但我認為有關它的詳細信息在這種情況下沒有用處。 請注意,我正在使用viewLifecycleOwner
分段
class DashboardFragment : Fragment() {
lateinit var binding: FragmentDashboardBinding
private val viewModel: DashboardUserViewModel by lazy {
ViewModelProvider(this).get(DashboardUserViewModel::class.java)
}
private val observer = Observer<DashboardUserViewModel.Action> {
// Tried but I would like to have a more elegant solution
//if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED)
it?.let {
when (it) {
DashboardUserViewModel.Action.QRCODE -> navigateToQRScanner()
DashboardUserViewModel.Action.ORDER -> TODO()
DashboardUserViewModel.Action.TOILETTE -> TODO()
}
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = this
viewModel.action.observe(viewLifecycleOwner, observer)
// Tried but still having the issue
//viewModel.action.reObserve(viewLifecycleOwner, observer)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
// Tried but still having the issue
//viewModel.action.removeObserver(observer)
}
private fun navigateToQRScanner() {
log("START QR SCANNER")
findNavController().navigate(LoginFragmentDirections.actionLoginToPrivacy())
}
}
當我關閉打開的片段(使用 findNavController().navigateUp())時,會立即調用 DashboardFragment 的 Observe.onChanged 並再次打開片段。
我已經檢查了這個問題並嘗試了上述鏈接中的所有建議解決方案(如您在注釋代碼中所見)。 只有這個解決方案有效,但它不是很優雅,並迫使我每次都進行檢查。
我想嘗試一個更可靠和最優的解決方案。
請記住,在該線程中沒有生命周期實現。
這就是LiveData
的工作方式,它是一個價值持有者,它持有最后一個價值。
如果您需要消耗您的對象,以便該操作僅觸發一次,請考慮將 object 包裝在Consumable
中,如下所示
class ConsumableValue<T>(private val data: T) {
private val consumed = AtomicBoolean(false)
fun consume(block: ConsumableValue<T>.(T) -> Unit) {
if (!consumed.getAndSet(true)) {
block(data)
}
}
}
然后您將 LiveData 定義為
val action: LiveData<ConsumableValue<Action>>
get() = mutableAction
private val mutableAction = MutableLiveData<ConsumableValue<Action>>()
然后在你的觀察者中,你會做
private val observer = Observer<ConsumableValue<DashboardUserViewModel.Action>> {
it?.consume { action ->
when (action) {
DashboardUserViewModel.Action.QRCODE -> navigateToQRScanner()
DashboardUserViewModel.Action.ORDER -> TODO()
DashboardUserViewModel.Action.TOILETTE -> TODO()
}
}
}
更新
找到了弗朗西斯在這里回答的不同且仍然有用的實現。 看一看
之所以會出現此問題,是因為如果有任何數據隨時可用,LiveData 總是將可用數據發布給觀察者。 之后它將發布更新。 我認為這是預期的工作,因為即使在問題跟蹤器中提出了錯誤,這種行為也沒有得到修復。 但是,SO 中的開發人員建議了許多解決方案,我發現這個很容易適應並且實際上工作得很好。
viewModel.messagesLiveData.observe(viewLifecycleOwner, {
if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) {
//Do your stuff
}
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.