![](/img/trans.png)
[英]Changing LiveData in Activity doesn't notify observer in child Fragment
[英]Fragment. getViewLifeCycleOwner doesn't prevent multiple calls of LiveData Observer
我使用 Clean Architecture、LiveData、Navigation 组件和底部导航视图。
我正在创建一个带有三个选项卡的简单应用程序。 默认情况下,第一个选项卡 Fragment 使用某些 API 加载用户数据。 当我转到另一个选项卡然后返回到第一个选项卡片段时,我看到, observe
返回一个新数据!
当我切换回第一个选项卡时,我需要observe
不要再次返回数据! 我究竟做错了什么? 请问你能帮帮我吗?
Ps 对于导航,我使用来自navigation-advanced-sample 的示例,并且在切换选项卡后没有调用onDestroy
。
Observe LiveData from ViewModel in Fragment一文中的第一个解决方案说:
一种适当的解决方案是使用 getViewLifeCycleOwner() 作为 LifeCycleOwer,同时观察 onActivityCreated 中的 LiveData,如下所示。
我使用以下代码,但它对我不起作用:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Timber.d("onActivityCreated")
viewModel.getProfileLive().observe(viewLifecycleOwner, observer)
}
文章架构组件陷阱 - 第 1 部分中的第二个解决方案建议使用重置现有观察者并在 onDestroyView() 中手动取消订阅观察者。 但它对我也不起作用......
ProfileFragment.kt
class ProfileFragment : DaggerFragment() {
@Inject
lateinit var viewModel: ProfileFragmentViewModel
private val observer = Observer<Resource<Profile>> {
when (it.status) {
Resource.Status.LOADING -> {
Timber.i("Loading...")
}
Resource.Status.SUCCESS -> {
Timber.i("Success: %s", it.data)
}
Resource.Status.ERROR -> {
Timber.i("Error: %s", it.message)
}
}
};
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.d("onCreate")
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Timber.d("onCreateView")
return inflater.inflate(R.layout.fragment_profile, container, false)
}
fun <T> LiveData<T>.reObserve(owner: LifecycleOwner, observer: Observer<T>) {
removeObserver(observer)
observe(owner, observer)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Timber.d("onViewCreated")
viewModel.getProfileLive().observe(viewLifecycleOwner, observer)
// viewModel.getProfileLive().reObserve(viewLifecycleOwner, observer)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Timber.d("onActivityCreated")
}
override fun onDestroyView() {
super.onDestroyView()
Timber.d("onDestroyView")
// viewModel.getProfileLive().removeObserver(observer)
}
override fun onDestroy() {
super.onDestroy()
Timber.d("onDestroy")
}
override fun onDetach() {
super.onDetach()
Timber.d("onDetach")
}
}
ProfileFragmentViewModel.kt
class ProfileFragmentViewModel @Inject constructor(
private val profileUseCase: ProfileUseCase
) : ViewModel() {
init {
Timber.d("Init profile VM")
}
fun getProfileLive() = profileUseCase.getProfile()
}
配置文件用例
class ProfileUseCase @Inject constructor(
private val profileRepository: ProfileRepository
) {
fun getProfile(): LiveData<Resource<Profile>> {
return profileRepository.getProfile()
}
}
ProfileRepository.kt 。 class ProfileRepository @Inject 构造函数(私有 val loginUserDao:LoginUserDao,私有 val profileDao:ProfileDao,){
fun getProfile(): LiveData<Resource<Profile>> =
liveData(Dispatchers.IO)
{
emit(Resource.loading(data = null))
val profile = profileDao.getProfile()
// Emit Success result...
}
}
这是因为Fragment Lifecycle 的工作方式。 当您从片段来回移动时,将再次调用onViewCreated()
。 在onViewCreated
您正在调用viewModel.getProfileLive()
,它从存储库返回实时数据并观察它。
由于每次移回Fragment时onViewCreated()
都会被调用,因此您对viewModel.getProfileLive()
调用viewModel.getProfileLive()
被调用,然后再次调用存储库,这再次触发了 Fragment 中的observe
方法。
为了解决这个问题,在你的ViewModel 中创建一个LiveData变量,将它设置为从Repository返回的Live Data 。 在Fragment 中观察ViewModel的LiveData 变量,而不是从Repository返回的变量。 这样,您的observe
方法将在第一次并且仅在您的存储库中的数据值发生变化时触发。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.