android-fragments 仅在单击按钮时更改LiveData的值,但即使在KotlinAndroid中的片段的onCreateView上也会调用观察器的onChange

yduiuuwa  于 2022-11-14  发布在  Android
关注(0)|答案(1)|浏览(200)

我的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上也被调用。
可能的原因是什么?

cedebl8k

cedebl8k1#

问题在于,LiveData会在您观察它时推送 * 新 * 值,但它也会在您 * 第一次 * 观察它时推送 * 最近的值 *,或者如果观察者的Lifecycle * 恢复 * 且数据在暂停后发生了变化。
因此,当你将toastMessage的值设置为1时,它会保持不变--而且ViewModel的生存期比Fragment长(这就是关键所在!),所以当你重新创建Fragment时,它会observetoastMessage的当前值,看到它当前是1,并显示一个吐司。
问题是你不想把它作为一个持久的数据状态来使用--你想让它成为一个一次性的事件,当你观察它的时候,你会 * 消费 * 它,所以吐司只会在你按下按钮的时候显示一次。这是LiveData的一个棘手的问题,已经有很多的解决方法、类、库等等来让它工作
这里有一个Android开发者的old post here,讨论了这个用例的问题,以及可用的变通方法和不足之处--如果有人感兴趣的话!但是就像上面说的那样,这些都已经过时了,他们建议遵循官方的指导方针。
官方的说法是:

  • 在ViewModel上触发事件
  • VM更新包括要显示的消息的UI状态
  • UI观察此更新,显示消息,并通知VM已显示该消息
  • VM更新UI状态,删除消息

这并不是处理可消耗事件的唯一方法,但这是他们推荐的方法,而且相当简单。因此,您可能希望执行以下操作:
第一个
您还可能希望创建吐司状态的枚举,而不仅仅是使用数字,这样更容易阅读--您甚至可以将它们的字符串ID放在枚举中:
第一个
它可以更清晰和自我记录比只是使用数字,你知道吗?

相关问题