我对android片段Backstack的工作方式遇到了一个很大的问题,对于提供的任何帮助将不胜感激。

假设您有3个片段
[1] [2] [3]
我希望用户能够导航[1] > [2] > [3],但在返回的途中(按返回按​​钮)[3] > [1]

就像我想象的那样,这将通过在创建将片段addToBackStack(..)带入XML定义的片段持有者的事务时不调用[2]来实现。

现实情况似乎是,如果我不希望当用户在[2]上按“后退”按钮时再次显示[3],则我不能在显示片段addToBackStack的事务中调用[3]。这似乎完全违反直觉(也许来自iOS世界)。

无论如何,如果我这样做,当我从[1] > [2]转到并按回去时,我会按预期返回[1]

如果我输入[1] > [2] > [3],然后按回去,则跳回[1](如预期)。
现在,当我尝试从[2]再次跳转到[1]时,就会发生奇怪的行为。首先,在显示[3]之前简要显示[2]。如果此时我按回去,则显示[3],如果再次按回去,则应用程序退出。

谁能帮我了解这里的事吗?

这是我的主要 Activity 的布局xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:orientation="vertical" >

<fragment
        android:id="@+id/headerFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        class="com.fragment_test.FragmentControls" >
    <!-- Preview: layout=@layout/details -->
</fragment>
<FrameLayout
        android:id="@+id/detailFragment"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"

        />



更新
这是我通过导航继承​​构建的代码
    Fragment frag;
    FragmentTransaction transaction;


    //Create The first fragment [1], add it to the view, BUT Dont add the transaction to the backstack
    frag = new Fragment1();

    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.commit();

    //Create the second [2] fragment, add it to the view and add the transaction that replaces the first fragment to the backstack
    frag = new Fragment2();

    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.addToBackStack(null);
    transaction.commit();


    //Create third fragment, Dont add this transaction to the backstack, because we dont want to go back to [2]
    frag = new Fragment3();
    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.commit();


     //END OF SETUP CODE-------------------------
    //NOW:
    //Press back once and then issue the following code:
    frag = new Fragment2();
    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.addToBackStack(null);
    transaction.commit();

    //Now press back again and you end up at fragment [3] not [1]

非常感谢

最佳答案

说明:这是怎么回事?

如果我们牢记.replace()与文档中知道的.remove().add()相等:



那么发生的事情是这样的(我在碎片中添加数字以使其更清楚):

// transaction.replace(R.id.detailFragment, frag1);
Transaction.remove(null).add(frag1)  // frag1 on view

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag1).add(frag2).addToBackStack(null)  // frag2 on view

// transaction.replace(R.id.detailFragment, frag3);
Transaction.remove(frag2).add(frag3)  // frag3 on view

(这里所有误导性的东西开始发生)

请记住,.addToBackStack()仅保存事务而不是片段本身!现在,我们在布局上添加了frag3:
< press back button >
// System pops the back stack and find the following saved back entry to be reversed:
// [Transaction.remove(frag1).add(frag2)]
// so the system makes that transaction backward!!!
// tries to remove frag2 (is not there, so it ignores) and re-add(frag1)
// make notice that system doesn't realise that there's a frag3 and does nothing with it
// so it still there attached to view
Transaction.remove(null).add(frag1) //frag1, frag3 on view (OVERLAPPING)

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag3).add(frag2).addToBackStack(null)  //frag2 on view

< press back button >
// system makes saved transaction backward
Transaction.remove(frag2).add(frag3) //frag3 on view

< press back button >
// no more entries in BackStack
< app exits >

可能的解决方案

考虑实现 FragmentManager.BackStackChangedListener 来监视后向堆栈中的更改,并在 onBackStackChanged() 方法中应用您的逻辑:
  • 跟踪交易计数;
  • 通过名称 FragmentTransaction.addToBackStack(String name);
  • 检查特定交易
  • 07-27 13:39