Android中MutableLiveData第二次无法向Fragment传值的问题排查
问题原因分析
你的问题核心出在LiveData的默认行为上:当你给MutableLiveData设置的新值和当前保存的旧值相等时,LiveData不会触发观察者的回调。比如第一次发送了AudioModeStatus("1"),第二次还是发送同样数据的AudioModeStatus,Fragment就收不到通知。另外,onSuccessSettingResponse里循环两次设置stateLiveData.value,后面的赋值会直接覆盖前面的,导致只有最后一个状态能被Fragment收到,而且如果这个状态和之前的一样,也不会触发回调。
解决方案
方案1:用Event包装类(推荐,不拆分LiveData)
创建一个Event类来包装你的状态,确保每次发送都是新的事件对象,即使内部数据相同,LiveData也会触发回调:
// 通用的Event包装类 open class Event<out T>(private val content: T) { var hasBeenHandled = false private set fun getContentIfNotHandled(): T? { return if (hasBeenHandled) { null } else { hasBeenHandled = true content } } fun peekContent(): T = content } // 在ViewModel里修改LiveData类型 override val stateLiveData: MutableLiveData<Event<CameraR2Status>> = MutableLiveData() // 发送状态时用Event包装 override fun onSuccessAudioMode(response: CardStatusResponse?) { stateLiveData.value = Event(AudioModeStatus(response?.status.toString())) } override fun onSuccessUpdatedRecordingStatus(response: CardStatusResponse?) { stateLiveData.value = Event(RecordingStatus(response?.status.toString())) } override fun onSuccessSettingResponse(response: SettingsResponse?) { response?.let { it.cmd.forEachIndexed { index, item -> if (item == "2007") { stateLiveData.value = Event(AudioModeStatus(it.status[index])) } } it.cmd.forEachIndexed { index, item -> if (item == "2001") { stateLiveData.value = Event(RecordingStatus(it.status[index])) } } } }
然后在Fragment里处理Event,确保只处理一次:
private fun onRoveR2CameraResponse(event: Event<BaseViewModel.CameraR2Status>) { event.getContentIfNotHandled()?.let { state -> when (state) { is BaseViewModel.CameraR2Status.AudioModeStatus -> { r2VideoControlWidget.showAudioStatusIcon(state.data) } is BaseViewModel.CameraR2Status.RecordingStatus -> { showLiveVideoWhenR2Connected() when (state.data) { "1" -> r2VideoControlWidget.showPlayStopButton(true) "0" -> r2VideoControlWidget.showPlayStopButton(false) } } } } }
方案2:拆分独立的LiveData
如果觉得包装类麻烦,可以给每个状态单独创建LiveData,这样各个状态的更新互不干扰,也不会出现覆盖问题:
class Rove2LiveVideoViewModelImpl @Inject constructor( private val roveR2UseCase: RoveR2UseCase, private val roveR2LiveVideoUseCase: RoveR2LiveVideoUseCase, private val appPreference: AppPreference ) : Rove2LiveVideoViewModel(), RoveR2UseCase.Callback, RoveR2LiveVideoUseCase.Callback { // 拆分独立的LiveData val audioModeLiveData: MutableLiveData<String> = MutableLiveData() val recordingStatusLiveData: MutableLiveData<String> = MutableLiveData() init { roveR2UseCase.setCallback(this) roveR2LiveVideoUseCase.setCallback(this) } override fun onSuccessAudioMode(response: CardStatusResponse?) { audioModeLiveData.value = response?.status.toString() } override fun onSuccessUpdatedRecordingStatus(response: CardStatusResponse?) { recordingStatusLiveData.value = response?.status.toString() } override fun onSuccessSettingResponse(response: SettingsResponse?) { response?.let { it.cmd.forEachIndexed { index, item -> if (item == "2007") { audioModeLiveData.value = it.status[index] } if (item == "2001") { recordingStatusLiveData.value = it.status[index] } } } } }
Fragment里分别观察:
rove2LiveVideoViewModel.apply { getR2CameraConnectedOrNot() observe(audioModeLiveData) { status -> r2VideoControlWidget.showAudioStatusIcon(status) } observe(recordingStatusLiveData) { status -> showLiveVideoWhenR2Connected() r2VideoControlWidget.showPlayStopButton(status == "1") } }
额外优化点
onSuccessSettingResponse里原来的两次循环可以合并成一次,避免重复遍历列表:
override fun onSuccessSettingResponse(response: SettingsResponse?) { response?.let { it.cmd.forEachIndexed { index, item -> when(item) { "2007" -> audioModeLiveData.value = it.status[index] "2001" -> recordingStatusLiveData.value = it.status[index] } } } }
内容的提问来源于stack exchange,提问作者MARSH
相关产品推荐
相关产品推荐

