为什么 livedata observe 会触发两次?
Why is livedata observe triggered twice?
我有一个在片段上调用的实时数据对象。第一次没问题,只触发一次,第二次进入fragment触发了两次,不明白为什么。
这是我称之为观察的地方:
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()
})
}
每当您的片段被创建时,您 运行 这个:
viewModel.getVideosData()
viewModel.videosData.observe(viewLifecycleOwner, Observer {
//second time I enter the fragment it triggers his twice
videoCategoryAdapter.loadItems(it)
})
我假设 getVideosData
是一些从数据库或其他东西获取数据的异步操作,在另一个 coroutine/thread 中。在这种情况下,当该方法将 LiveData
更新为 videosData.value = it
时,它将在稍后
下一行是您 observe
LiveData 的位置 - 如果它当前有一个值,它将立即传送,并且 lambda 将获得 运行。当 getVideosData
完成并设置一个值时,观察者将 运行 再次 .
你没有第一次看到这个的原因可能是因为你的 LiveData
没有初始值 (val videosData = MutableLiveData<List<DtoCelebrityResource>>()
) 所以当你第一次 observe
它时, lambda 不触发。然后当设置视频数据时,你得到回调,所以它只发生一次。
但是因为 LiveData 现在有一些数据,而 ViewModel
的目的是在 Fragments 和 Activity 关闭时保持状态,下次打开该片段时 videosData
在你第一次调用observe
时有初始值吗?所以你看到了,还有更新。
有很多方法可以解决这个问题,但是在 videosData
上调用 distinctUntilChanged()
(这会创建一个 LiveData,它仅在数据根据其 equals
function) 可能足以解决它。例如
// 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()
我有一个在片段上调用的实时数据对象。第一次没问题,只触发一次,第二次进入fragment触发了两次,不明白为什么。
这是我称之为观察的地方:
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()
})
}
每当您的片段被创建时,您 运行 这个:
viewModel.getVideosData()
viewModel.videosData.observe(viewLifecycleOwner, Observer {
//second time I enter the fragment it triggers his twice
videoCategoryAdapter.loadItems(it)
})
我假设 getVideosData
是一些从数据库或其他东西获取数据的异步操作,在另一个 coroutine/thread 中。在这种情况下,当该方法将 LiveData
更新为 videosData.value = it
时,它将在稍后
下一行是您 observe
LiveData 的位置 - 如果它当前有一个值,它将立即传送,并且 lambda 将获得 运行。当 getVideosData
完成并设置一个值时,观察者将 运行 再次 .
你没有第一次看到这个的原因可能是因为你的 LiveData
没有初始值 (val videosData = MutableLiveData<List<DtoCelebrityResource>>()
) 所以当你第一次 observe
它时, lambda 不触发。然后当设置视频数据时,你得到回调,所以它只发生一次。
但是因为 LiveData 现在有一些数据,而 ViewModel
的目的是在 Fragments 和 Activity 关闭时保持状态,下次打开该片段时 videosData
在你第一次调用observe
时有初始值吗?所以你看到了,还有更新。
有很多方法可以解决这个问题,但是在 videosData
上调用 distinctUntilChanged()
(这会创建一个 LiveData,它仅在数据根据其 equals
function) 可能足以解决它。例如
// 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()