首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >弹出片段后的多个LiveData观察者

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

Stack Overflow用户
提问于 2018-08-17 17:35:38
回答 3查看 15.6K关注 0票数 21

问题

摘要:多个LiveData观察者在导航到新片段、弹出新片段并返回到原始片段之后在片段中被触发。

详细信息:架构由以下部分组成MainActivity它承载了一个HomeFragment作为起始目的地在MainActivity的导航图。在HomeFragment中是以编程方式膨胀的PriceGraphFragment。HomeFragment正在使用导航组件启动新的子片段ProfileFragment。按下back键时,ProfileFragment会弹出,应用程序会返回到托管PriceGraphFragment的HomeFragment。PriceGraphFragment是观察者被多次调用的地方。

我正在记录观察者发出的HashMap的哈希码,当我转到配置文件片段、弹出配置文件片段并返回到价格片段时,它显示了两个唯一的哈希码。这与我在不启动配置文件片段的情况下旋转屏幕时从HashMap中看到的散列代码相反。

实现

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

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

2. ViewModel在片段中创建(PriceGraphFragment)。ViewModel已被记录,并且具有多个观察者的数据仅在ViewModel中初始化一次。

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

3. 侦听来自ViewModel在原始片段(PriceGraphFragment)中。它被多次调用,但是当片段被加载时,它应该只有一个观察者。

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

尝试的解决方案

1. 创建片段%sViewModel在onCreate()方法。

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

2. 使用片段的活动和子片段的父片段创建ViewModel。

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

3. 创建对片段的观察者的移动方法onCreate()和onActivityCreated()方法。

4. 使用viewLifecycleOwner而不是this对于LifecycleOwner在该方法中observe(@NonNull LifecycleOwner owner, @NonNull Observer observer)

5. 在与片段相反的ViewModel中存储显示为重复的HashMap数据。

6. 方法启动该子片段。ChildFragmentManagerSupportFragmentManager(在活动级别上)。

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

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

下一步

这个问题可能与创建嵌套的ChildFragment(PriceGraphFragment)中ParentFragment%s(HomeFragment)onViewCreated()

ParentFragment

代码语言:javascript
复制
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对象。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-22 14:59:37

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

已解决的问题

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

之前:

代码语言:javascript
复制
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()
    }
...
}

之后:

代码语言:javascript
复制
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. 创建ViewModel%s在onCreate()与之相对的是onCreateView()父片段和子片段。
  2. 正在初始化子片段(PriceFragment)的数据请求(Firebase Firestore查询)onCreate()而不是onViewCreated()但仍然只在以下情况下才这样做saveInstanceState是空。

非因素

有几个项目被建议,但事实证明对解决这个bug没有影响。

  1. 创建观察者在onActivityCreated()。我把我的留在里面onViewCreated()子片段(PriceFragment)的。
  2. 使用viewLifecycleOwner在观察者创造。我使用的是子片段(PriceFragment)的this之前。即使viewLifecycleOwner不会影响这个bug,这似乎是总体上的最佳实践,所以我保留了这个新的实现。
票数 7
EN

Stack Overflow用户

发布于 2018-08-21 02:13:16

这基本上是架构中的一个bug。你可以阅读更多关于它的内容here..。您可以使用以下命令来解决此问题getViewLifecycleOwner而不是在observer

如下所示:

代码语言:javascript
复制
mViewModel.methodToObserve().observe(getViewLifecycleOwner(), new Observer() {
        @Override
        public void onChanged(@Nullable Type variable) {

并将此代码放入onActivityCreated()因为使用getViewLifecycleOwner需要一个视图。

票数 10
EN

Stack Overflow用户

发布于 2021-02-26 10:32:44

最好初始化视图模型并在中观察实时数据对象onCreate

代码语言:javascript
复制
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProvider(this).get(MyFragmentViewModel::class.java)

        // 'viewLifecycleOwner' is not available here, so use 'this'
        viewModel.myLiveData.observe(this) {
            // Do something
        }
    }

但是,无论您在何处初始化视图模型,无论是在onCreate或者onViewCreated,它仍然会为您提供相同的视图模型对象,因为它在片段的生命周期中只创建了一次。

最重要的部分是观察onCreate。因为onCreate仅在创建片段时调用,则调用observe只有一次。

onViewCreated无论是在创建片段时还是从后台堆栈取回片段时(在弹出其上的片段之后),都会调用。如果您在onViewCreated它将在从后台堆栈返回时立即从上一次调用中获取您的实时数据所持有的现有数据。

取而代之的是,使用onViewCreated仅用于从视图模型获取数据。因此,每当片段出现时,无论是在创建时还是从后台堆栈返回时,它都会获取最新的数据。

代码语言:javascript
复制
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewModel.fetchData()

        ...
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51892478

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档