BottomNavigationView + 在切换标签时保存Fragment状态

5
我正在使用 BottomNavigationView 来创建底部选项卡。
1)标签 1 - 从服务器获取数据并在 RecyclerView 中显示。
2)标签 2 - 从服务器获取 URL 并加载到 Webview 中。
3)标签 3 - 从服务器获取数据并在 RecyclerView 中显示。
4)标签 4 - 使用 PreferenceFragmentCompat 的设置屏幕。
为了保存这些片段的状态,当用户切换选项卡时,我使用了来自这篇博客的以下代码:
Fragment.SavedState 保存到 SparseArray<Fragment.SavedState>中。
Fragment.State currentFragmentState = getSupportFragmentManager().saveFragmentInstanceState(currentFragment)

当用户导航回先前的标签页时,再次恢复状态。
fragment.setInitialSavedState(savedState)

getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.container_fragment, fragment, tag)
        .commit();

我所看到的是只有标签 4(使用 PreferenceFragmentCompat 的设置屏幕)保持了状态 - 如果我向下滚动到第十个项目,然后导航到其他片段并再次回到设置屏幕,我会在顶部看到第十个位置。
然而,前三个标签会再次进行网络服务调用并重新加载所有内容。此外,我还可以看到前三个标签的 onCreateView 方法的 Bundle savedInstanceState 参数也不为 null。

我的问题如下:
1)PreferenceFragmentCompat(第四个标签)如何自动恢复状态?
2)我应该如何利用前三个标签中非空的 Bundle savedInstanceState 参数,才能像第四个标签那样恢复状态?
3)为什么前三个标签不能自动恢复状态?

编辑:
我正在使用与博客相同的代码。
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                switch (item.getItemId()) {

                    case R.id.navigation_item_1:                       
                        swapFragments(new Fragment1(), item.getItemId(), TAG_1);
                        return true;

                    case R.id.navigation_item_2:      
                        swapFragments(new Fragment2(), item.getItemId(), TAG_2);
                        return true;

                    case R.id.navigation_item_3:
                        swapFragments(new Fragment3(), item.getItemId(), TAG_3);
                        return true;

                    case R.id.navigation_item_4:
                        swapFragments(new Fragment4(), item.getItemId(), TAG_4);
                        return true;

                    default:
                        return false;
                }
            }
        });

        private void swapFragments(Fragment fragment, int itemId, String tag) {
            if (getSupportFragmentManager().findFragmentByTag(tag) == null) {
                saveFragmentState(itemId, tag);
                createFragment(fragment, itemId, tag);
            }
        }

        private void saveFragmentState(int itemId, String tag) {
            Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container_fragment);
            if (currentFragment != null) {
                fragmentStateArray.put(currentSelectedItemId, getSupportFragmentManager().saveFragmentInstanceState(currentFragment));
            }

            currentSelectedItemId = itemId;
        }

        private void createFragment(Fragment fragment, int itemId, String tag) {
            fragment.setInitialSavedState(fragmentStateArray.get(itemId));

            getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.container_fragment, fragment, tag)
                    .commit();
        }

你在前三个片段中使用了哪个生命周期方法来获取数据? - Milan Kundacina
数据正在onActivityCreated方法中获取。 - Harsh4789
你能发布代码片段吗? - Milan Kundacina
我已经更新了问题,并附上保存和恢复片段状态的代码。 - Harsh4789
嗨@Harsh4789,我想知道你是否已经解决了它,因为我也遇到了同样的问题,而且我卡住了,我需要帮助,谢谢。 - Kennedy Mathinya
2个回答

0
尝试将前3个片段的获取操作移动到onCreate方法中。
原因是当您再次进入片段时,会调用onActivityCreated并再次获取数据,然后更新recyclerview,这会重置并将您移回recyclerview的开头。
但是,如果您将其命名为onCreate,则获取数据应仅在第一次进入片段时发生,因此它不会更新recyclerview,也不会重置它。

'replace' 方法从容器中移除一个片段,因此每次用户切换选项卡时都会执行 onCreate()。 - Harsh4789

0

你现在正在用这段代码替换片段

getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.container_fragment, fragment, tag)
        .commit();

你可以像这样的代码一样添加片段而不是替换它们

getSupportFragmentManager()
        .beginTransaction()
        .add(R.id.container_fragment, fragment, tag)
        .commit();

这将会添加片段而不是替换它,因此片段状态将被保存。

1
谢谢您的回复,但为什么第四个片段要使用“replace”来恢复状态呢?此外,我在这里分享的博客也是使用“replace”方法,并成功地管理了状态。 - Harsh4789

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接