为了账号安全,请及时绑定邮箱和手机立即绑定

Android Fragment Back Stack的问题

Android Fragment Back Stack的问题

牧羊人nacy 2019-10-14 15:06:57
我对android片段Backstack的工作方式遇到了一个很大的问题,对于提供的任何帮助将不胜感激。假设您有3个片段[1] [2] [3]我希望用户能够导航[1] > [2] > [3]但在返回的途中(按返回按钮)[3] > [1]。就像我想象的那样,这可以通过addToBackStack(..)在创建将片段[2]带入XML定义的片段持有者的事务时不调用来实现。现实情况似乎是,如果我不想[2]在用户按下“后退”按钮时再次出现[3],则我不能调用addToBackStack显示片段的事务[3]。这似乎完全违反直觉(也许来自iOS世界)。无论如何,如果我这样做,当我离开[1] > [2]并按回去时,我会按[1]预期到达。如果我走了[1] > [2] > [3]然后按回去,我跳回了[1](按预期)。现在,当我尝试[2]从再次跳到时,就会发生奇怪的行为[1]。首先在[3]显示之前简要显示[2]。如果此时我按回,[3]将显示,如果我再次按回,则该应用程序退出。谁能帮我了解这里的事吗?这是我的主要活动的布局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();
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

说明:这是怎么回事?

如果我们牢记这.replace()一点.remove().add(),我们将通过文档了解这一点:


替换添加到容器中的现有片段。这本质上与调用remove(Fragment)所有当前添加的片段相同,这些片段在此处添加了相同的参数containerViewId,然后又add(int, Fragment, String)添加了相同的参数。


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


// 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()methode中应用您的逻辑:


跟踪交易计数;

通过名称检查特定交易 FragmentTransaction.addToBackStack(String name);

等等。


查看完整回答
反对 回复 2019-10-14
?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

对!!!经过多拉头发,我终于弄清楚了如何使其正常工作。


似乎在按下后退按钮时并未从视图中删除片段[3],因此您必须手动进行操作!


首先,不要使用replace(),而要分别使用remove和add。似乎replace()无法正常工作。


下一步是重写onKeyDown方法,并在每次按下后退按钮时删除当前片段。


@Override

public boolean onKeyDown(int keyCode, KeyEvent event)

{

    if (keyCode == KeyEvent.KEYCODE_BACK)

    {

        if (getSupportFragmentManager().getBackStackEntryCount() == 0)

        {

            this.finish();

            return false;

        }

        else

        {

            getSupportFragmentManager().popBackStack();

            removeCurrentFragment();


            return false;

        }




    }


    return super.onKeyDown(keyCode, event);

}



public void removeCurrentFragment()

{

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();


    Fragment currentFrag =  getSupportFragmentManager().findFragmentById(R.id.detailFragment);



    String fragName = "NONE";


    if (currentFrag!=null)

        fragName = currentFrag.getClass().getSimpleName();



    if (currentFrag != null)

        transaction.remove(currentFrag);


    transaction.commit();


}

希望这可以帮助!


查看完整回答
反对 回复 2019-10-14
  • 3 回答
  • 0 关注
  • 408 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信