PopBackStack 但保留 android 中的第一个片段

PopBackStack but keep the first fragment in android

我在做分片交易,后台是这样的:

fragA => fragB => fragC => fragD

从 fragD

回来后,我想 return 到 fragA
fragD => onBackPress => fragA

所以,我尝试了如下代码:

getChildFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

但是它清除了所有的后台堆栈,我怎样才能将第一个片段保留在后台堆栈中?非常感谢

因为 "back stack" 具有类似堆栈的行为...后进先出...您添加到返回堆栈的最后一个片段将首先从返回堆栈中弹出。您将需要通过指定自己的行为来手动实现所需的行为。使用 FragmentManager class 方法并不难。

如果您 "tag" 您将片段添加到交易中...

 fragmentTransaction.add(new FragmentA(), "FragmentA_Tag");

您稍后可以确定在按下后退按钮时显示哪个片段...

FragmentA f = fragmentManager.findFragmentByTag("FragmentA_Tag");
if(f != null){
    f.show();
}

您如何确定显示哪个片段完全取决于您。您可以跟踪当前可见片段,也可以使用 Fragment class 的 isHidden 方法...顺便说一句,我在这里谈论的是原生片段,不支持库的片段.

后台包含有关交易的记录,而不是片段本身。 所以你不应该将第一个事务的记录 (null -> fragA) 添加到 backstack。 并且所有其他交易的记录都应该添加到后台。 在这种情况下,那么你 preformpopBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); android 删除了除 fragA 之外的所有片段,因为没有任何关于 fragA 是如何添加的记录。

例如您可以执行以下操作:

  • 添加 fragA 但不将其添加到 backStack。所以它总是在
    activity,并且不会对后退按钮做出反应。
  • 当您打开 fragD 时,您应该 clear fragment BackStack。因此,当您从 D frag 按下后退按钮时,您会返回到 A。

P.S。还有其他方法可以做你想做的事。这取决于...

几天前,我开始学习 Android 中的片段。我也遇到了这个问题。在这里,我展示了我的解决方案以及我如何解决这个问题。如果我的代码不正确,请修复。此时我们有什么?活动,许多片段及其后台。我们想从抽屉菜单中打开每个片段,并从后台清除所有其他片段。但是,我们必须只持有一个 Home 片段。当我们停留在 Home fragment 上并且用户按下后退按钮时,应用程序将关闭。

Activity.class

protected void onCreate(Bundle savedInstanceState)
{
    ...
    // adding Home fragment without adding transaction into backstack
    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.container, HomeFragment.newInstance("args"), null);
    ft.commit();
}

@Override
public void onBackPressed() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        finish();
    }
}

public void addFragmentFromMenu(Fragment fragment){
    String backStateName =  fragment.getClass().getName();
    clearBackStack();
    FragmentManager manager = getSupportFragmentManager();
    if(manager.getBackStackEntryCount()> 0)
    {
        boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);

        if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
            //fragment not in back stack, create it.
            addFragment(fragment, manager, backStateName);
        }
    }
    else // no fragments
    {
        addFragment(fragment, manager, backStateName);
    }
}

public void addFragment(Fragment fragment, FragmentManager manager, String backStateName)
{
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.container, fragment, backStateName);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(backStateName);
    ft.commit();
}

public void clearBackStack() {
    getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}

然后点击抽屉菜单项

@Override
public boolean onNavigationItemSelected(MenuItem item) {

    int id = item.getItemId();

    if (id == R.id.nav_camera) {
        addFragmentFromMenu(CameraFragment.newInstance("cam1", "cam2"));
    } else if (id == R.id.nav_gallery) {
        addFragmentFromMenu(TestFragment.newInstance("test1","test2"));
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

我做了以下方法。清除所有片段然后添加第一个主页片段

FragmentManager fm = getActivity().getSupportFragmentManager();
                    fm.popBackStack(Constants.TAG_HOME, FragmentManager.POP_BACK_STACK_INCLUSIVE);

                    ((MainActivity) activity).manageFragment(new HomeFragment(), Constants.TAG_HOME);
 //        write down below function in main activity              
     public void manageFragment(Fragment fragment, String tag) {

            FragmentManager fragmentManager = getSupportFragmentManager();
            if (!fragmentManager.popBackStackImmediate(tag, 0)) {

                FragmentTransaction ft = fragmentManager.beginTransaction();
                ft.add(R.id.content_frame, fragment, tag);
                ft.addToBackStack(tag);
                ft.commit();

            }
        }

1) 使用以下代码添加第一个片段

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
        android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
        if (fm.findFragmentById(R.id.fragment_container) != null) {
            ft.hide(fm.findFragmentById(R.id.fragment_container));
        }
        ft.add(R.id.fragment_container, new OneFragment(),OneFragment.class.getCanonicalName())
                .addToBackStack(OneFragment.class.getCanonicalName()).commit();

2) 使用以下代码从第一个片段添加第二个片段

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                    android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                    if (fm.findFragmentById(R.id.fragment_container) != null) {
                        ft.hide(fm.findFragmentById(R.id.fragment_container));
                    }
                    ft.add(R.id.fragment_container,new TwoFragment(),TwoFragment.class.getCanonicalName())
.addToBackStack(TwoFragment.class.getCanonicalName()).commit();

3) 使用以下代码从第二个片段添加第三个片段

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                if (fm.findFragmentById(R.id.fragment_container) != null) {
                    ft.hide(fm.findFragmentById(R.id.fragment_container));
                }
                ft.add(R.id.fragment_container, new ThreeFragment(),ThreeFragment.class.getCanonicalName())
                        .addToBackStack(ThreeFragment.class.getCanonicalName()).commit();

4) 使用以下代码从第三个片段添加第四个片段

android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
                android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
                if (fm.findFragmentById(R.id.fragment_container) != null) {
                    ft.hide(fm.findFragmentById(R.id.fragment_container));
                }
                ft.add(R.id.fragment_container, new FourFragment(),ThreeFragment.class.getCanonicalName())
                        .addToBackStack(FourFragment.class.getCanonicalName()).commit();

5) onBackPressed() 请写下代码

@Override
    public void onBackPressed() {
        hideKeyboard(MainActivity.this);
        Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);

        if (currentFragment.getClass().getName().equalsIgnoreCase(FourFragment.class.getName())) { // Using this code come from third fragment to first fragment
            Fragment f = this.getSupportFragmentManager().findFragmentByTag(TwoFragment.class.getCanonicalName());
            if (f != null) {
                this.getSupportFragmentManager().popBackStackImmediate(f.getClass().getCanonicalName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
        }else {
            super.onBackPressed();
        }
    }

看了很多帖子,我是这样想的:

在 fragC => fragD 方法中,做两个事务:

1 清除返回堆栈,fragC => fragA

2 fragA => fragD

但是这样一来,fragA原来的状态可能会被破坏

public static void changeFragCtoD(FragmentManager fm, Fragment fragD){
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    FragmentTransaction fragmentTransaction = fm.beginTransaction();
    fragmentTransaction
            .replace(R.id.containerViewId, new fragAClass())
            .commit();

    FragmentTransaction fragmentTransaction = fm.beginTransaction();
    fragmentTransaction
            .replace(R.id.containerViewId, fragD)
            .addToBackStack(fragD.getClass().getName())
            .commit();
}

现在按回 fragD 会回到 fragA。

记住我的话,完整的 FragmentTransaction 被添加到后台堆栈,而不仅仅是片段,这意味着即使您在单个事务中添加和删除片段,调用 poBackStack() 也会反转完整的事务。在其参数中传递标签会弹出所有交易,直到标记的交易甚至弹出标记的交易(如果 FragmentManager.POP_BACK_STACK_INCLUSIVE 添加到参数) 所以更多的是关于你如何添加它而不是你如何删除它。 参见 Performing Fragment Transactions

我知道现在回答您的问题为时已晚,但这可能对其他人有所帮助。 由于这几天一直在寻找解决方案...我已经使用for循环解决了这个问题,我认为这是最简单的方法。

首先,这样初始化一个整数

int count = getSupportFragmentManager().getBackStackEntryCount();

其中 getBackStackEntryCount() 将计算事务数。

然后在调用 fragD 中的 FragmentTransaction 方法之前添加这个 for 循环

for (int i = 0; i < count; i++){
                getSupportFragmentManager().popBackStack();
            }

for 循环将为您完成任务,popBackStack() 将 return 您转到 fragA

看起来像这样

int count = getSupportFragmentManager().getBackStackEntryCount();
            for (int i = 0; i < count; i++){
                getSupportFragmentManager().popBackStack();
            }
            fragmentTransaction.replace(R.id.frame_layout, new FoodFragment(), "Food").addToBackStack(null);
            fragmentTransaction.commit();

您可以覆盖 onbackpressed(Mainactivity)并使用片段管理器的 getBackStackEntryCount(),您可以检查它是否不等于 1 并仅在该条件下弹出堆栈。

@Override
public void onBackPressed() {
  if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
     if (!(getSupportFragmentManager().getBackStackEntryCount() == 1)) {
      getSupportFragmentManager().popBackStack() ;
    }
  }    
}