带有 Viewpager2 的关键 FragmentStateAdapter 的片段不再存在

Posted

技术标签:

【中文标题】带有 Viewpager2 的关键 FragmentStateAdapter 的片段不再存在【英文标题】:Fragment no longer exists for key FragmentStateAdapter with Viewpager2 【发布时间】:2020-04-16 13:59:38 【问题描述】:

我正在为我的项目使用 ViewPager2。我需要在带有 viewpager2 的片段中使用嵌套片段。在我尝试在片段(不是嵌套片段)之间导航之前,它就像魅力一样。

第一次在片段之间导航后,应用程序崩溃并出现下面解释的错误。

包含嵌套片段的片段 OnCreateView 方法:

View view = inflater.inflate(R.layout.orders_fragment, null);

ViewPager2 viewPager = view.findViewById(R.id.childViewPager);

TabLayout tabs = view.findViewById(R.id.tabs);

SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager(),getLifecycle());

viewPager.setAdapter(sectionsPagerAdapter);

TabLayoutMediator.TabConfigurationStrategy tabConfigurationStrategy = (tab, position) -> 

    String[] order_activity_tabs = getResources().getStringArray(R.array.situations);

    for (int i=0; i<order_activity_tabs.length; i++) 

        if(i==position)
            tab.setText(order_activity_tabs[i]);

    
;

TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabs, viewPager, tabConfigurationStrategy);
tabLayoutMediator.attach();

return view;

当我返回包含嵌套片段的片段时,它会崩溃

 java.lang.IllegalStateException: Fragment no longer exists for key f#0: unique id 4fbe17b8-5e22-4e07-a543-4a79445ad39c
        at androidx.fragment.app.FragmentManagerImpl.getFragment(FragmentManagerImpl.java:365)
        at androidx.viewpager2.adapter.FragmentStateAdapter.restoreState(FragmentStateAdapter.java:549)
        at androidx.viewpager2.widget.ViewPager2.restorePendingState(ViewPager2.java:350)
        at androidx.viewpager2.widget.ViewPager2.dispatchRestoreInstanceState(ViewPager2.java:375)
        at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4045)
        at android.view.View.restoreHierarchyState(View.java:20253)
        at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:548)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:907)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)

FragmentStatePagerAdapter 有解决方案,但 FragmentStateAdapter 没有。而且因为我不能覆盖 FragmentStateAdapter 中的方法,所以实现这个解决方案是不可能的。

感谢您阅读本文。任何帮助表示赞赏。

【问题讨论】:

在访问片段之前,首先检查它是否存在于片段堆栈中。 感谢您的回复。但我不确定如何做到这一点? 【参考方案1】:

将 viewpager2 与 FragmentStateAdapter 一起使用与 FragmentStatePagerAdapter 具有相似的行为

其实解决这个问题有两种方法

第一个是在我们的 viewpager2 中设置 setSaveEnabled() 为 false

viewpager2.setSaveEnabled(false)

另一个在我们的适配器上覆盖restoreState并返回null

检查:https://developer.android.com/reference/androidx/viewpager2/adapter/FragmentStateAdapter

【讨论】:

不幸的是,restoreState 被声明为 final 我对这个答案的赞成票数量感到惊讶。 1. 如果您这样做,应用程序将无法保存和重新创建前一个片段的状态。 2. 正如@JE42 所说,restoreState 被定义为最终版本。 我认为它更多的是出于调试目的而不是替换片段的保存状态 不建议在产品版本中这样做,如果设置为false则不会保存此视图的状态,这意味着当您从另一个屏幕返回到具有视图的片段时-pager,它将丢失以前的数据。【参考方案2】:

通过实施新的导航组件解决了我的问题。它本身处理片段转换。遇到此问题的任何人都可以更改其导航方法。

【讨论】:

您能解释一下您的解决方案吗?【参考方案3】:

您所要做的就是使用以下属性在布局文件中设置您的 viewpager2

android:saveEnabled="true"

【讨论】:

不应该将值设置为“false”吗?【参考方案4】:

尝试在 FragmentStateAdapter 中的片段参数中调用 requireActivity()

private inner class ScreenSlidePagerAdapter(fa: FavoriteFragment) : FragmentStateAdapter(fa.requireActivity())

【讨论】:

【参考方案5】:

我也遇到了同样的问题。原因是当重新创建包含的片段时,它的 childFragmentManager 也是如此。 FragmentStateAdapter 在传递的片段管理器中查找它恢复状态的片段。

我的解决方案是让它使用 Activity 的 FragmentManager 而不是 Fragment 的,例如使用像这样的 Activity 的构造函数

class MyAdapter(f: Fragment) : FragmentStateAdapter(f.activity!!)

【讨论】:

以上是关于带有 Viewpager2 的关键 FragmentStateAdapter 的片段不再存在的主要内容,如果未能解决你的问题,请参考以下文章

NotifyDataSetChanged 在带有 Viewpager2 的 FragmentStateAdapter 中不起作用

带有片段和 Jetpack 导航的 Viewpager2:恢复片段而不是重新创建它们

带有viewpager2 android的导航图

ViewPager2 崩溃

修改子项时 ViewPager2 转到第一页

让 viewpager2 响应标签点击事件