【问题标题】:Why is livedata observe triggered twice?为什么 livedata 观察会触发两次?
【发布时间】:2022-01-11 16:57:25
【问题描述】:

我在片段上调用了一个 livedata 对象。第一次工作正常,它只触发一次,但第二次进入片段它触发两次,不明白为什么。

这就是我所说的观察:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    return inflater.inflate(R.layout.activity_train_with_famous_detail, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    setupUi(view)
    (activity as TrainingWithFamousActivity).hideToolbar()
    setupListCategoryVideos(view)
    viewModel.getVideosData()
    viewModel.videosData.observe(viewLifecycleOwner, Observer {
        //second time I enter the fragment it triggers his twice
        videoCategoryAdapter.loadItems(it)
    })
    viewModel.videoSelected?.let { loadTrainWithFamousDetailsData(it) }
}

这是我的视图模型中的方法:

val videosData = MutableLiveData<List<DtoCelebrityResource>>()
fun getVideosData() {
    showLoader()

    trainingWithFamousUseCase
        .build(this)
        .executeWithError({
            videosData.value = it
            hideLoader()
        }, {
            hideLoader()
        })
}

【问题讨论】:

  • 您确定两次接收 LiveData 的是同一个片段实例吗?片段是否可能存在两次,每个实例都接收到 LIveData?
  • 第三次输入会触发三次吗?

标签: android kotlin mvvm android-livedata


【解决方案1】:

每当你的片段被创建时,你运行这个:

viewModel.getVideosData()
viewModel.videosData.observe(viewLifecycleOwner, Observer {
    //second time I enter the fragment it triggers his twice
    videoCategoryAdapter.loadItems(it)
})

我假设getVideosData 是一些异步操作,它在另一个协程/线程中从数据库或其他东西中获取数据。在这种情况下,当该方法将LiveData 更新为videosData.value = it 时,将稍后

下一行是 observe LiveData - 如果它当前有一个值,它将立即交付,并且 lambda 将开始运行。当getVideosData 完成并设置一个值时,观察者将再次运行


您第一次没有看到这个的原因可能是因为您的 LiveData 没有初始值 (val videosData = MutableLiveData&lt;List&lt;DtoCelebrityResource&gt;&gt;()),所以当您第一次看到 observe 时,lambda 不会触发。然后当设置视频数据时,你会得到回调,所以它只发生一次。

但是因为 LiveData 现在有一些数据,并且 ViewModel 的目的是在片段和活动等关闭时保持状态,所以下次打开片段时 videosData 确实首次调用observe 时有一个初始值。所以你看到了,还有更新。

有很多方法可以解决这个问题,但是在 videosData 上调用 distinctUntilChanged()(它创建一个 LiveData,仅在数据根据其 equals 函数“更改”时推送更新)可能就足够了解决它。例如

// internal mutable version
private val _videosData = MutableLiveData<List<DtoCelebrityResource>>()
// exposed immutable version, with the "emit distinct values" transformation
val videosData: LiveData<List<DtoCelebrityResource>> = _videosData.distinctUntilChanged()

【讨论】:

    猜你喜欢
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多