Android 在底部选项卡导航中将嵌套片段重新附加到其片段容器时,嵌套片段的状态将丢失

Android 在底部选项卡导航中将嵌套片段重新附加到其片段容器时,嵌套片段的状态将丢失,android,android-fragments,android-lifecycle,android-nested-fragment,fragmentmanager,Android,Android Fragments,Android Lifecycle,Android Nested Fragment,Fragmentmanager,我正在开发具有以下UI结构的应用程序: 一个名为FoodActivity的活动 此活动执行。因此,可以显示三类食物:水果、肉和鱼 活动有一个大的片段容器,当用户与底部选项卡交互时,我将水果、肉和鱼的片段附在容器中 每个外部片段(鱼、肉和鱼)显示片段之间的导航:它可以显示水果列表以及所选水果的详细信息。 因此,外部Fragments有另一个Fragments容器,我将Fragments附加在其中,用于水果列表或水果细节 因此,它是一个主要的活动,它有一个很大的片段容器,我在其中交换片段

我正在开发具有以下UI结构的应用程序:

  • 一个名为FoodActivity的
    活动
    • 活动执行。因此,可以显示三类食物:水果、肉和鱼
    • 活动
      有一个大的
      片段
      容器,当用户与底部选项卡交互时,我将水果、肉和鱼的
      片段附在容器中
  • 每个外部
    片段
    (鱼、肉和鱼)显示
    片段之间的导航:它可以显示水果列表以及所选水果的详细信息。
    
    • 因此,外部
      Fragments
      有另一个
      Fragments
      容器,我将
      Fragments
      附加在其中,用于水果列表或水果细节
因此,它是一个主要的
活动
,它有一个很大的
片段
容器,我在其中交换
片段
,而这些片段又嵌套了其他
片段

要使用选项卡从一个外部
片段
切换到另一个(即:从水果切换到肉),我在外部
片段
容器中执行片段事务:

private void switchFragment(Fragment fragment, String fragmentTag) {
    final FragmentManager fm = getSupportFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();

    ft.replace(R.id.fragment_outer, fragment, fragmentTag);
    ft.commit();
}
问题是在切换第一级
片段时,其
子片段管理器的状态不会保持

例如,想象一下: -我从FuitFragment开始 -创建时,水果片段会附加嵌套的水果列表片段 -用户在嵌套的
Fragment
容器中从FruitListFragment导航到FruitDetailFragment -用户切换到另一个选项卡 -用户切换回“水果”选项卡 -FuitFragment的子项“FragmentManager*”不会自动将FrootDetailFragment放入嵌套的片段容器中

更具体地说,当切换回外部
片段时:

  • 调用
    onCreate
    ,其中
    savedInstance
    ==null
  • 调用onCreateView
,并使用
savedInstance
==null 因此,当调用外部
片段
onCreate
方法时,我无法判断是否要附加子
片段
(就像人们通常对
活动
所做的那样)。
此外,如果我不附加它(使用实例变量检查我是否切换回它),子
片段
容器将只是空的

实验和笔记

  • 我已经试验过,如果在附加外部片段事务时将其添加到backbackback,在切换回它时,
    onCreate
    方法不会被调用,并且子
    FragmentManager
    将记住并附加它以前拥有的片段。 但是,我无法按照将其添加到backbackback

  • setRetainInstance
    设置为true不会产生任何效果

那么,我应该如何正确地恢复子项的状态
FragmentManager


是我做错了什么,还是Android中围绕嵌套片段的所有内容都没有得到很好的支持(或者有点破损),我根本不应该使用嵌套片段提供导航?

正如阿巴斯指出的,问题是我使用了
替换
在片段之间切换

我已在活动中更改为代码,以放置外部片段,并且它可以工作:

private void showChildFragment(int itemId) {
    final FragmentManager fragmentManager = getSupportFragmentManager();
    final FragmentTransaction  transaction = fragmentManager.beginTransaction();

    final Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_outer);
    if (currentFragment != null) {
        Log.v(TAG, "Detaching item #" + currentFragment);
        currentFragment.setMenuVisibility(false);
        currentFragment.setUserVisibleHint(false);
        transaction.detach(currentFragment);
    }

    // Do we already have this fragment?
    final String tag = makeFragmentTag(container.getId(), itemId);
    Fragment fragment = fragmentManager.findFragmentByTag(tag);
    if (fragment == null) {
        fragment = createFragmentForViewId(itemId);
        Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        transaction.add(container.getId(), fragment, tag);
    } else {
        Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        transaction.attach(fragment);
    }
    fragment.setMenuVisibility(true);
    fragment.setUserVisibleHint(true);

    transaction.commitAllowingStateLoss();
    fragmentManager.executePendingTransactions();
}

private Fragment createFragmentForViewId(int itemId) {
    switch (itemId) {
        case FRAGMENT_ID_LIBRARY:
            return LibraryNavigationFragment.createInstance();
        case FRAGMENT_ID_FEED:
            return WebAppFragment.createInstance("feed");
        case FRAGMENT_ID_SUGGEST:
            return WebAppFragment.createInstance("suggest");
        default:
            throw new IllegalArgumentException();

    }
}

这段代码几乎是从
android.support.v4.app.FragmentPagerAdapter
复制粘贴而来,就像
ViewPagers
使用片段一样工作

使用getChildFragmentManager()它不会崩溃

private void switchFragment(Fragment fragment, String fragmentTag) {
    final FragmentManager fm = getChildFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();

    ft.replace(R.id.fragment_outer, fragment, fragmentTag);
    ft.commit();
}

一个简单的解决方案是根据需要将
replace()
方法调用替换为
add()
attach()
remove()
detach
detach()
method调用保留片段的状态,只对UI隐藏。没错,阿巴斯。我是在读《碎片密码》时得出这个结论的。我已经用有效的代码发布了答案,但是如果你想发布你的答案,我会将其标记为有效答案。你有完整的实现,你可以告诉我吗?我需要实现这一点。