片段 addToBackStack() 和 popBackStackImmediate() 不起作用

Posted

技术标签:

【中文标题】片段 addToBackStack() 和 popBackStackImmediate() 不起作用【英文标题】:Fragment addToBackStack() and popBackStackImmediate() not working 【发布时间】:2014-12-28 21:35:53 【问题描述】:

我目前正在使用一个ActionBarActivity 和多个Fragments 构建android (14 ListFragment 和MapFragment,它们在单个@987654326 中交换@视图。

ActionBarActivity 自动替换/提交片段 A。然后,当用户点击按钮时,托管 Activity 替换/提交新的不同片段 B。我的目标是让用户在按下后立即返回片段 A后退按钮。

现在有一些代码。

主活动

public class MainActivity extends ActionBarActivity implements StopFragment.OnFragmentInteractionListener,
    StopItemFragment.OnFragmentInteractionListener 
...

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fragmentManager = getFragmentManager();
        fragmentManager.enableDebugLogging(true);
        ...
        if (fragmentManager.findFragmentById(R.id.content_frame) == null) 
            StopItemFragment list = StopItemFragment.newInstance(null); //A - extends ListFragment
            fragmentManager.beginTransaction()
                .replace(R.id.content_frame, list)
                .addToBackStack(null)
                .commit();
        
        ...

        @Override
        public void onFragmentInteraction(String id) 
        selectItem(Integer.parseInt(id));
        


       private void selectItem(int position) 
       StopFragment fragment = StopFragment.newInstance(null, null); //B - extends Fragment
       ...
       fragmentManager.beginTransaction()
            .replace(R.id.content_frame, fragment)
            .commit();

       ...
       

问题

即使调用addToBackStack(),当我在fragment B时,我也无法回到fragment A。MainActivity被直接关闭。 然而,我试图自己管理后台堆栈,但没有运气。我可以看到片段在堆栈上,但是如果我调用popBackStackImmediate(),片段 A 会弹出并且片段事务不会执行。 (第一次后按没有任何反应,第二次活动关闭)

我还附上了 FragmentManager logcat:http://pastebin.com/hFLHprL8

【问题讨论】:

【参考方案1】:

对于那些仍在寻找解决方案的人。

在主Activity 类(托管片段)中,只需覆盖onBackPressed()

@Override
public void onBackPressed() 
    if (getFragmentManager().getBackStackEntryCount() > 0 )
        getFragmentManager().popBackStack();
     else 
        super.onBackPressed();
    

fragment中没有onBackPressed()方法,该方法只针对activity。所以,当我们按下返回键时,会显示activity的默认行为,即

你要么去以前的活动(如果有的话)要么去应用程序 将退出。

现在我们需要重写这个方法来告诉activity,当我们按下返回键时,如果返回堆栈中有任何碎片,则将它们弹出(这就是addToBackStack()出现的时候)。否则遵循默认行为。

【讨论】:

谢谢。我想知道为什么android文档没有提到这个重要的东西?或者我只是想念它......【参考方案2】:

试试这个(注意 add 而不是 replace 用于 fragmentA,addToBackStack() 用于 fragmentB)

StopItemFragment list = StopItemFragment.newInstance(null); //A - extends ListFragment
        fragmentManager.beginTransaction()
            .add(R.id.content_frame, list)
            .commit();

StopFragment fragment = StopFragment.newInstance(null, null); //B - extends Fragment
   ...
   fragmentManager.beginTransaction()
        .replace(R.id.content_frame, fragment)
        .addToBackStack("FragmentB")
        .commit();

【讨论】:

这样我添加了堆栈片段 B 而不是 A。来自FragmentTransaction 文档:addToBackStack(): Add this transaction to the back stack. This means that the transaction will be remembered after it is committed, and will reverse its operation when later popped off the stack.【参考方案3】:

我不得不手动致电FragmentManager 中的beginTransaction()commit()。 通过覆盖onBackPressed()解决:

@Override
public void onBackPressed() 
    ...
    if (fragmentManager.getBackStackEntryCount() > 1)
        fragmentManager.popBackStackImmediate();
        fragmentManager.beginTransaction().commit();
     else 
        //handle finish
        finish(); // Closes app
    

【讨论】:

popBackStackImmediatepopBackStack 慢,为了避免性能问题,尽可能使用popBackStack【参考方案4】:

如果您正在为 addToBackStack() 和 popBackStack() 苦苦挣扎,那么只需使用

FragmentTransaction ft =getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, new HomeFragment(), "Home");
ft.commit();`

在 OnBackPressed() 中的 Activity 中按标签找出片段,然后做你的事情

Fragment home = getSupportFragmentManager().findFragmentByTag("Home");

if (home instanceof HomeFragment && home.isVisible()) 
    // do you stuff

更多信息https://github.com/DattaHujare/NavigationDrawer 我从不使用 addToBackStack() 来处理片段。

【讨论】:

【参考方案5】:

popBackStack()popBackStackImmediatly() 的原因是您没有将该片段(您想要弹出的片段)添加到 backStack。为此,您必须在进行事务时调用 addToBackStack() 以添加/替换您的片段。

【讨论】:

【参考方案6】:

首先,我想非常感谢突出显示的 [Nick] 的回答(低声誉无法在下面发表评论),因为它帮助我知道实际上有一些东西没有在Android 文档。

其次,现在是 2019 年,在 Androidx 的 Preferences 中以类似的方式磕磕绊绊后,我找了很长时间都找不到任何东西,直到我同时检查了这个问题和一个 official sample code in Kotlin,这个问题导致了线索和示例代码的方式实际上是我的解决方案,就像一个非常小的覆盖的魅力,希望它对那些正在寻找官方解决方案的人也有帮助

@Override
public boolean onSupportNavigateUp() 

    if (getSupportFragmentManager().popBackStackImmediate())
        return true;
    

    return super.onSupportNavigateUp();

Aforementioned code in Java (Screenshot)

附:在使用了至少 5 年以上之后,我在 stacksoverflow 上的第一个答案 ^^

【讨论】:

以上是关于片段 addToBackStack() 和 popBackStackImmediate() 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

addToBackStack 没有导航回正确的片段

android fragment addToBackStack(null):如何将同一个片段添加到堆栈中一次?

在通过 ActionBar 添加的 Fragment 上调用 addToBackStack()

片段回栈和替换

上一个片段edittext焦点问题

替换片段的高程值错误