我的ViewModel中有一个LiveData:-
private val _toastMessage = MutableLiveData<Long>()
val toastMessage
get() = _toastMessage
这是我改变它的值的唯一方法(在片段中点击提交按钮):-
fun onSubmitClicked(<params>){
Log.i(LOG_TAG, "submit button clicked")
uiScope.launch {
if(!myChecksForEditTextValuesSucceeded())
{
_toastMessage.value = 0
}else{
_toastMessage.value = 1
}
}
}
在这个片段中,我有一个LiveData的观察者:
transactionViewModel.toastMessage.observe(viewLifecycleOwner, Observer { it->
when{
(it.compareTo(0) == 0) -> Toast.makeText(context, resources.getString(R.string.toast_msg_transaction_not_inserted), Toast.LENGTH_SHORT).show()
else -> Toast.makeText(context, resources.getString(R.string.toast_msg_transaction_inserted), Toast.LENGTH_SHORT).show()
}
})
理想情况下,我希望这个Observer的onChange只在我的片段上单击submit按钮时被调用,但是,正如我所看到的,它甚至在我的片段的onCreateView上也被调用。
可能的原因是什么?
1条答案
按热度按时间cedebl8k1#
问题在于,
LiveData
会在您观察它时推送 * 新 * 值,但它也会在您 * 第一次 * 观察它时推送 * 最近的值 *,或者如果观察者的Lifecycle
* 恢复 * 且数据在暂停后发生了变化。因此,当你将
toastMessage
的值设置为1
时,它会保持不变--而且ViewModel
的生存期比Fragment
长(这就是关键所在!),所以当你重新创建Fragment
时,它会observe
为toastMessage
的当前值,看到它当前是1
,并显示一个吐司。问题是你不想把它作为一个持久的数据状态来使用--你想让它成为一个一次性的事件,当你观察它的时候,你会 * 消费 * 它,所以吐司只会在你按下按钮的时候显示一次。这是
LiveData
的一个棘手的问题,已经有很多的解决方法、类、库等等来让它工作这里有一个Android开发者的old post here,讨论了这个用例的问题,以及可用的变通方法和不足之处--如果有人感兴趣的话!但是就像上面说的那样,这些都已经过时了,他们建议遵循官方的指导方针。
官方的说法是:
这并不是处理可消耗事件的唯一方法,但这是他们推荐的方法,而且相当简单。因此,您可能希望执行以下操作:
第一个
您还可能希望创建吐司状态的枚举,而不仅仅是使用数字,这样更容易阅读--您甚至可以将它们的字符串ID放在枚举中:
第一个
它可以更清晰和自我记录比只是使用数字,你知道吗?