[英]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.