本文介绍了弹出片段后的多个LiveData观察者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要:导航到新的片段,弹出新的片段,然后返回到原始片段.

Summary: Multiple LiveData Observers are being triggered in a Fragment after navigating to a new Fragment, popping the new Fragment, and returning to the original Fragment.

详细信息:该体系结构由 MainActivity 组成,在MainActivity的导航图. HomeFragment中有一个以编程方式夸大的 PriceGraphFragment . HomeFragment 正在使用导航组件启动新的子片段 ProfileFragment .背面按一下,将弹出ProfileFragment,应用程序返回到承载PriceGraphFragment的HomeFragment. PriceGraphFragment是多次调用Observer的地方.

Details: The architecture consists of MainActivity that hosts a HomeFragment as the start destination in the MainActivity's navigation graph. Within HomeFragment is a programmatically inflated PriceGraphFragment. The HomeFragment is using the navigation component to launch a new child Fragment ProfileFragment. On back press the ProfileFragment is popped and the app returns to the HomeFragment hosting the PriceGraphFragment. The PriceGraphFragment is where the Observer is being called multiple times.

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

I'm logging the hashcode of the HashMap being emitted by the Observer and it is showing 2 unique hashcodes when I go to the profile Fragment, pop the profile Fragment, and return to the price Fragment. This is opposed to the one hashcode seen from the HashMap when I rotate the screen without launching the profile Fragment.

  1. 导航组件可在HomeFragment中启动新的ProfileFragment.

  1. Navigation component to launch new ProfileFragment within HomeFragment.

view.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_homeFragment_to_profileFragment, null))

view.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_homeFragment_to_profileFragment, null))

ViewModel . ViewModel已被记录,并且具有多个Observer的数据仅在ViewModel中初始化了一次数据.

ViewModel creation in Fragment (PriceGraphFragment). The ViewModel has been logged and the data that has multiple Observers only has data initialized in the ViewModel once.

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java)}

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java)}

在原始片段(PriceGraphFragment)中收听来自 ViewModel 的数据.这被多次调用,但是预计只有在加载Fragment时才有一个Observer.

Listen for data from ViewModel in original Fragment (PriceGraphFragment). This is being called multiple times, however it is only expected to have one Observer when the Fragment is loaded.

priceViewModel.graphLiveData.observe(this, Observer { priceGraphDataMap: HashMap<Exchange, PriceGraphLiveData>? -> // This is being called multiple times.})

priceViewModel.graphLiveData.observe(this, Observer { priceGraphDataMap: HashMap<Exchange, PriceGraphLiveData>? -> // This is being called multiple times.})

尝试的解决方案

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

  1. Creating the Fragment's ViewModel in the onCreate() method.priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.java)
  2. Creating the ViewModel using the Fragment's activity and the child Fragment's parent Fragment.
    priceViewModel = ViewModelProviders.of(activity!!).get(PriceDataViewModel::class.java)

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

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

  • https://github.com/googlesamples/android-architecture-components/Issues/47
  • https://medium.com/@BladeCoder/architecture- components-pitfalls-part-1-9300dd969808
  • https://plus.google.com/109072532559844610756/posts/Mn9SpcA5cHz
  • Similar Issues and Proposed Solutions

    • https://github.com/googlesamples/android-architecture-components/issues/47
    • https://medium.com/@BladeCoder/architecture-components-pitfalls-part-1-9300dd969808
    • https://plus.google.com/109072532559844610756/posts/Mn9SpcA5cHz
      • 也许该问题与在 ParentFragment 的( HomeFragment >)onViewCreated()?
      • Perhaps the issue is related to creating the nested ChildFragment (PriceGraphFragment) in the ParentFragment's (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()
      }
      

      • 测试用RxJava可观察对象替换LiveData对象.
      • 推荐答案

        首先,谢谢所有在此发布的人.您的建议和建议相结合,在过去5天内帮助我解决了该错误,因为其中涉及多个问题.

        First off, thank you to everyone who posted here. It was a combination of your advice and pointers that helped me solve this bug over the past 5 days as there were multiple issues involved.

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

        之后:

        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()
            }
        ...
        }
        
        1. 相对于父片段和子片段onCreateView(),在onCreate()中创建 ViewModel .

        onCreate()而不是onViewCreated()中初始化子片段(PriceFragment)的数据请求(Firebase Firestore查询)数据,但仅当 saveInstanceState null时仍会这样做.

        Initializing request for data (Firebase Firestore query) data of child Fragment (PriceFragment) in onCreate() rather than onViewCreated() but still doing so only when saveInstanceState is null.

        非因素

        提出了一些建议,但结果对解决此错误没有影响.

        Non Factors

        A couple items were suggested but turned out to not have an impact in solving this bug.

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

        1. Creating Observers in onActivityCreated(). I'm keeping mine in onViewCreated() of the child Fragment (PriceFragment).

        观察者创建中使用viewLifecycleOwner.我之前使用的是子片段(PriceFragment)的this.即使viewLifecycleOwner不会影响此错误,但总体上似乎是最佳实践,因此我保留了此新实现.

        Using viewLifecycleOwner in the Observer creation. I was using the child Fragment (PriceFragment)'s this before. Even though viewLifecycleOwner does not impact this bug it seems to be best practice overall so I'm keeping this new implementation.

        这篇关于弹出片段后的多个LiveData观察者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-04 22:15