弹出片段后的多个LiveData观察者

问题描述 投票:6回答:2

Issue

摘要:导航到新片段,弹出新片段并返回到原始片段后,片段中会触发多个LiveData观察器。

详细信息:该体系结构由MainActivity组成,MainActivity将HomeFragment作为MainActivity导航图中的起始目标。 HomeFragment中是一个以编程方式夸大的PriceGraphFragment。 HomeFragment正在使用导航组件来启动新的子Fragment ProfileFragment。在背面按下,弹出ProfileFragment,应用程序返回到托管PriceGraphFragment的HomeFragment。 PriceGraphFragment是多次调用Observer的地方。

我正在记录Observer发出的HashMap的哈希码,当我转到配置文件片段时,它会显示2个唯一的哈希码,弹出配置文件Fragment,然后返回价格片段。当我在不启动配置文件Fragment的情况下旋转屏幕时,这与从HashMap看到的一个哈希码相反。

Implementation

  1. 导航组件在HomeFragment中启动新的ProfileFragment。 view.setOnClickListener(Navigation.createNavigateOnClickListener( R.id.action_homeFragment_to_profileFragment, null))
  2. 在Fragment中创建ViewModel(PriceGraphFragment)。已记录ViewModel,并且具有多个Observers的数据仅在ViewModel中初始化一次数据。 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java) }
  3. 从原始Fragment(PriceGraphFragment)中的ViewModel中侦听数据。这被多次调用,但是只有在加载Fragment时才会有一个Observer。 priceViewModel.graphLiveData.observe( this, Observer { priceGraphDataMap: HashMap<Exchange, PriceGraphLiveData>? -> // This is being called multiple times. })

Attempted Solutions

  1. 在onCreate()方法中创建Fragment的ViewModel。 priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java)
  2. 使用Fragment的活动和子Fragment父Fragment创建ViewModel。 qazxsw poi qazxsw poi
  3. 将观察者创建到Fragment的onCreate()和onActivityCreated()方法的移动方法。
  4. 在方法priceViewModel = ViewModelProviders.of(activity!!).get(PriceDataViewModel::class.java)中使用priceViewModel = ViewModelProviders.of(parentFragment!!).get(PriceDataViewModel::class.java)而不是viewLifecycleOwner作为LifecycleOwner。
  5. 存储在与Fragment相对的ViewModel中显示为重复的HashMap数据。
  6. 使用thisobserve(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)(在活动级别)启动子Fragment。

Similar Issues and Proposed Solutions

Next Steps

ParentFragment

https://plus.google.com/109072532559844610756/posts/Mn9SpcA5cHz
  • 测试用RxJava observable替换LiveData对象。
android android-fragments kotlin android-navigation android-livedata
2个回答
7
投票

这基本上是架构中的一个错误。你可以阅读更多关于它onViewCreated()。你可以在override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) user = viewModel.getCurrentUser() if (savedInstanceState == null) { fragmentManager ?.beginTransaction() ?.replace(binding.priceDataContainer.id, PriceGraphFragment.newInstance()) ?.commit() } 中使用here代替这个来解决它。

像这样:

getViewLifecycleOwner

并将此代码放在observer中,因为使用mViewModel.methodToObserve().observe(getViewLifecycleOwner(), new Observer<Type>() { @Override public void onChanged(@Nullable Type variable) { 需要一个视图。


2
投票

首先,感谢发布在这里的所有人。这是您的建议和指针的组合,帮助我在过去5天内解决了这个错误,因为涉及多个问题。

Issues Resolved

  1. 在父Fragment(HomeFragment)中正确创建嵌套片段。

之前:

onActivityCreated()

后:

getViewLifecycleOwner
  1. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { if (savedInstanceState == null) { fragmentManager ?.beginTransaction() ?.add(binding.priceDataContainer.id, PriceGraphFragment.newInstance()) ?.commit() fragmentManager ?.beginTransaction() ?.add(binding.contentFeedContainer.id, ContentFeedFragment.newInstance()) ?.commit() } ... } 中创建ViewModel而不是为父子片段和子片段创建override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState == null && childFragmentManager.findFragmentByTag(PRICEGRAPH_FRAGMENT_TAG) == null && childFragmentManager.findFragmentByTag(CONTENTFEED_FRAGMENT_TAG) == null) { childFragmentManager.beginTransaction() .replace(priceDataContainer.id, PriceGraphFragment.newInstance(), PRICEGRAPH_FRAGMENT_TAG) .commit() childFragmentManager.beginTransaction() .replace(contentFeedContainer.id, ContentFeedFragment.newInstance(), CONTENTFEED_FRAGMENT_TAG) .commit() } ... }
  2. onCreate()而不是onCreateView()中初始化对子片段(PriceFragment)的数据(Firebase Firestore查询)数据的请求,但仅在saveInstanceState为null时仍然这样做。

Non Factors

建议了一些项目,但结果却没有解决这个问题的影响。

  1. onCreate()创建观察员。我将我的孩子片段(PriceFragment)保存在onViewCreated()中。
  2. 在Observer创建中使用onActivityCreated()。之前我正在使用儿童Fragment(PriceFragment)的onViewCreated()。虽然viewLifecycleOwner不会影响这个bug,但它似乎是最佳实践,所以我保留了这个新的实现。
© www.soinside.com 2019 - 2024. All rights reserved.