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

Ada*_*itz 11 android android-fragments kotlin android-navigation android-livedata

问题

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

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

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

履行

  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. })

试图解决方案

  1. onCreate()方法中创建FragmentViewModel. priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java)
  2. 使用Fragment的活动和子Fragment的父Fragment创建ViewModel.
    priceViewModel = ViewModelProviders.of(activity!!).get(PriceDataViewModel::class.java)

    priceViewModel = ViewModelProviders.of(parentFragment!!).get(PriceDataViewModel::class.java)

  3. 将观察者创建到Fragment的onCreate()onActivityCreated()方法的移动方法.
  4. 使用viewLifecycleOwner,而不是thisLifecycleOwner的方法observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer).
  5. 存储在与Fragment相对的ViewModel中显示为重复的HashMap数据.
  6. 使用ChildFragmentManagerSupportFragmentManager(在活动级别)启动子Fragment .

类似问题和建议的解决方案

下一步

  • 也许问题与创建嵌套ChildFragment(PriceGraphFragment中)ParentFragment的(HomeFragment)onViewCreated()

ParentFragment

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()
}
Run Code Online (Sandbox Code Playgroud)
  • 测试用RxJava observable替换LiveData对象.

Kvd*_*gen 8

这基本上是体系结构中的错误。您可以在此处了解更多信息。您可以在中使用getViewLifecycleOwner代替它来解决它observer

像这样:

mViewModel.methodToObserve().observe(getViewLifecycleOwner(), new Observer<Type>() {
        @Override
        public void onChanged(@Nullable Type variable) {
Run Code Online (Sandbox Code Playgroud)

并将此代码放到需要onActivityCreated()使用的getViewLifecycleOwner视图中。

  • 谢谢@KvidLingen,从我最初的帖子中您可以看到我已经尝试过 getViewLifecycleOwner 解决方案。我已经更新了我的初始帖子,以表明我还尝试了 `onActivityCreated()` 解决方案,但没有成功。 (3认同)

Ada*_*itz 7

首先,感谢所有在这里发帖的人。在过去的 5 天里,由于涉及多个问题,您的建议和指示的结合帮助我解决了这个错误。

问题已解决

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

前:

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()
    }
...
}
Run Code Online (Sandbox Code Playgroud)

后:

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()
    }
...
}
Run Code Online (Sandbox Code Playgroud)
  1. 创建视图模型S IN onCreate(),而不是onCreateView()家长和孩子都片段。

  2. 初始化对子 Fragment (PriceFragment) 的数据(Firebase Firestore 查询)数据的请求,onCreate()而不是onViewCreated()仅在saveInstanceStatenull时才这样做。

非因素

建议了几个项目,但结果表明对解决此错误没有影响。

  1. 创建观察员onActivityCreated()。我将我的保留在onViewCreated()子片段 (PriceFragment) 中。

  2. 使用viewLifecycleOwner观察创作。我之前使用的是子片段(PriceFragment)this。尽管viewLifecycleOwner不会影响此错误,但总体而言似乎是最佳实践,因此我将保留此新实现。