【问题标题】:Which method is being called after popBackStack?popBackStack 之后调用了哪个方法?
【发布时间】:2014-04-04 18:15:48
【问题描述】:

我有一个活动,我正在调用三个片段 - 每个片段相互依赖:

A(ctivity) -> f1(片段一,标题{is|should}:列表)-> f2(片段二,标题{is|should}:概述)-> f3(片段三,标题{is|)应该}:详细)

ATM我使用下面的方法调用向后跳转:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            FragmentManager fragmentManager = getSupportFragmentManager();
            if (fragmentManager.getBackStackEntryCount()>0){
                fragmentManager.popBackStack();
            }
    }
}

这很好用。

我正在像这样覆盖每个片段中的 ActionBar 标题:

ActionBar bar = getSherlockActivity().getSupportActionBar();
bar.setTitle(R.string.title_f3);

向前导航时(如上所示),这可以完美运行,但向后导航时,ActionBar 的标题不会更新:

f3 (title {is|should}: 细节) -> f2 (title {is}: 细节, {should}: 概览) -> f1 (title {is}: 细节, {should}: 列表)

显然我可以在显示片段时再次更新它。但是我的调试器永远不会停止在我想要的任何方法中,除了像 onResume() 这样调用的方法。

那么在 popBackStack() 之后的前一个片段中实际上是否有任何方法被调用?

【问题讨论】:

  • 如果您返回,也许您想为关闭选择一个答案! :)
  • 您好@OpenHaus,如果您对您的查询感到满意,您能否选择这个问题的答案,谢谢! :)

标签: java android android-fragments


【解决方案1】:

我知道这个答案有点晚了,但对于任何在这里导航的人来说这可能会有所帮助!

首先要做的是:popBackStack() 不会弹出一个片段,它会弹出一个片段事务。所以最后一个片段事务在被调用时被反转。如果您当前正在显示 FragmentA 并且您的交易是:

fragmentTransaction.replace(R.id.your_layout, fragmentB);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

它将用 FragmentB 替换 FragmentA,并将该事务(而不是片段)添加到后台堆栈。如果你然后点击返回按钮,它会从返回堆栈中弹出事务,即“用 FragmentB 替换这个 FragmentA”。本质上,该指令反转最后一个事务并将其从执行的事务堆栈中删除。如果原来的 FragmentA 仍然存在,它会使用那个。如果它被破坏了,它会重新生成一个。

所以,如果 Fragment 没有被销毁,那么在使用 popBackStack() 后调用该 Fragment,就会调用 onStart() 和 onResume() 方法。如果 Fragment 之前已被销毁,则生命周期方法将从 onAttach() 开始调用。这与在活动上按后退按钮相同。

现在重要的是,当我们从栈中弹出时,片段生命周期会发生什么?就像之前说的那样,片段事务被反转了:

场景 1:您的 fragmentB 在交易之前并不存在。 在这种情况下,在事务期间调用 onCreate() 和 onAttach() 方法,因此如果您调用 popBackStack() 并反转事务,片段将被销毁和分离(注意 FragmentA 可能已经存在,因此替换它不会像我们一样破坏它不撤消片段创建)。在这种情况下,生命周期方法将从 onAttach() 开始调用。

场景 2:您的 fragmentB 在交易之前已经存在。在这种情况下,片段不会被销毁,下次访问它时会调用 onStart() 和 onResume() 方法。

这个家伙在这里解释了一些关于使用 popbackstack() http://vinsol.com/blog/2014/09/19/transaction-backstack-and-its-management/ 和片段生命周期 http://vinsol.com/blog/2014/10/22/fragment-view-state-retention-a-dirty-solution/ 的事情。其他相关的帖子也值得一读!

【讨论】:

  • 我检查过了。在这种情况下,当片段没有被破坏时,当用户点击后退按钮和 popbackStack 运行时,片段 OnResume 永远不会被调用。我需要一种方法来调用我的界面函数来显示或隐藏工具栏。也许在 mainActivty 中使用“addOnBackStackChangedListener”就是答案。
【解决方案2】:

在您的 BaseActivity 中使用 addOnBackStackChangedListener 方法,该方法将在任何退栈更改时调用

getSupportFragmentManager().addOnBackStackChangedListener(
            new FragmentManager.OnBackStackChangedListener() {
                public void onBackStackChanged() {
                    FragmentManager fm = getSupportFragmentManager();

                    if (fm != null) {
                        int backStackCount = fm.getBackStackEntryCount();
                        if (backStackCount == 0) {
                            if (getSupportActionBar() != null) {
                                getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
                            }
                            setToolbarTittle(R.string.app_name);
                        } else {
                            if (getSupportActionBar() != null) {
                                getSupportActionBar().setHomeAsUpIndicator(R.drawable.back);
                            }
                        }
                    }
                }
            });

【讨论】:

    【解决方案3】:

    我的解决方法是先在片段中获取操作栏的当前标题,然后再将其设置为新标题。这样,一旦 Fragment 弹出,我就可以改回那个标题。

    @Override
    public void onResume() {
        super.onResume();
        // Get/Backup current title
        mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
                .getTitle();
        // Set new title
        ((ActionBarActivity) getActivity()).getSupportActionBar()
            .setTitle(R.string.this_fragment_title);
    }
    
    @Override
    public void onDestroy() {
        // Set title back
        ((ActionBarActivity) getActivity()).getSupportActionBar()
            .setTitle(mTitle);
    
        super.onDestroy();
    }
    

    【讨论】:

      【解决方案4】:

      您还可以阅读另外一个很好的source

      我认为,重要的一点是你在 Fragment B 上执行的事务的不同。如果是 add,那么 Fragment A 上不会调用生命周期方法,如果它是replace,你会收到一些关于这些方法的调用。

      【讨论】:

        【解决方案5】:

        我使用以下解决方法:

        1) 在第一个片段之上添加第二个片段之前设置第一个片段setHasOptionsMenu(false)

        2) 从第二个片段返回后,在onOptionsItemSelected() 中设置第一个片段setHasOptionsMenu(true)

        3) 应该调用第一个片段的onCreateOptionsMenu(),您可以在此处更改操作栏。

        但我想知道更好的解决方案。

        【讨论】:

        • 我现在的解决方案是覆盖onBackPressed() 方法并相应地设置标题。
        【解决方案6】:

        您可以在 android 文档 here 中找到漂亮的 Fragment 生命周期图。所以是的,如果片段从后台堆栈被带到前台,onCreateView()onActivityCreated()onStart()onResume() 会被调用。

        【讨论】:

        • 我知道生命周期和提到的方法。正如我在问题中详细描述的那样,这些方法都没有被调用。这就是我问的原因。
        • 我认为的方法是向您的片段添加自定义方法,覆盖 onBackPressed(或通过OnBackStackChangedListener),获取当前可见的片段并调用您的自定义方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-02
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        • 2020-03-27
        • 1970-01-01
        • 2018-10-05
        相关资源
        最近更新 更多