首页 文章

Android 4.2:嵌套片段的后台堆栈行为

提问于
浏览
98

在Android 4.2中,支持库支持嵌套片段see here . 我玩过它并发现了一个有关背堆和getChildFragmentManager()的有趣行为/错误 . 使用getChildFragmentManager()和addToBackStack(String name)时,通过按后退按钮,系统不会将后堆栈向下运行到前一个片段 . 另一方面,当使用getFragmentManager()和addToBackStack(String name)时,通过按后退按钮,系统将返回上一个片段 .

对我来说,这种行为是出乎意料的 . 通过按下设备上的后退按钮,我希望弹出最后添加到后端堆栈的片段,即使片段已添加到子片段管理器中的后端堆栈中也是如此 .

这种行为是否正确?这种行为是个错误吗?这个问题有解决方法吗?

使用getChildFragmentManager()的

示例代码:

public class FragmentceptionActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);

    final FrameLayout wrapper1 = new FrameLayout(this);
    wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT));
    wrapper1.setId(1);

    final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT);
    params.topMargin = 0;

    final TextView text = new TextView(this);
    text.setLayoutParams(params);
    text.setText("fragment 1");
    wrapper1.addView(text);

    setContentView(wrapper1);

    getSupportFragmentManager().beginTransaction().addToBackStack(null)
            .add(1, new Fragment1()).commit();
}

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper2 = new FrameLayout(getActivity());
        wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper2.setId(2);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 100;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 2");
        wrapper2.addView(text);

        return wrapper2;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(2, new Fragment2()).commit();
    }
}

public class Fragment2 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper3 = new FrameLayout(getActivity());
        wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper3.setId(3);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 200;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 3");
        wrapper3.addView(text);

        return wrapper3;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getChildFragmentManager().beginTransaction().addToBackStack(null)
                .add(3, new Fragment3()).commit();
    }
}

public class Fragment3 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper4 = new FrameLayout(getActivity());
        wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper4.setId(4);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 300;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 4");
        wrapper4.addView(text);

        return wrapper4;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getChildFragmentManager().beginTransaction().addToBackStack(null)
                .add(4, new Fragment4()).commit();
    }
}

public class Fragment4 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper5 = new FrameLayout(getActivity());
        wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper5.setId(5);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 400;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 5");
        wrapper5.addView(text);

        return wrapper5;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

}

使用getFragmentManager()的

示例代码:

public class FragmentceptionActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle arg0) {
    super.onCreate(arg0);

    final FrameLayout wrapper1 = new FrameLayout(this);
    wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT));
    wrapper1.setId(1);

    final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT);
    params.topMargin = 0;

    final TextView text = new TextView(this);
    text.setLayoutParams(params);
    text.setText("fragment 1");
    wrapper1.addView(text);

    setContentView(wrapper1);

    getSupportFragmentManager().beginTransaction().addToBackStack(null)
            .add(1, new Fragment1()).commit();
}

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper2 = new FrameLayout(getActivity());
        wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper2.setId(2);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 100;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 2");
        wrapper2.addView(text);

        return wrapper2;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(2, new Fragment2()).commit();
    }
}

public class Fragment2 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper3 = new FrameLayout(getActivity());
        wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper3.setId(3);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 200;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 3");
        wrapper3.addView(text);

        return wrapper3;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(3, new Fragment3()).commit();
    }
}

public class Fragment3 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper4 = new FrameLayout(getActivity());
        wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper4.setId(4);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 300;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 4");
        wrapper4.addView(text);

        return wrapper4;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getFragmentManager().beginTransaction().addToBackStack(null)
                .add(4, new Fragment4()).commit();
    }
}

public class Fragment4 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final FrameLayout wrapper5 = new FrameLayout(getActivity());
        wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT));
        wrapper5.setId(5);

        final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        params.topMargin = 400;

        final TextView text = new TextView(getActivity());
        text.setLayoutParams(params);
        text.setText("fragment 5");
        wrapper5.addView(text);

        return wrapper5;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

}

13 回答

  • 1

    此代码将导航片段管理器树并返回添加的最后一个片段,该片段具有可以从堆栈中弹出的任何片段:

    private FragmentManager getLastFragmentManagerWithBack(FragmentManager fm)
    {
      FragmentManager fmLast = fm;
    
      List<Fragment> fragments = fm.getFragments();
    
      for (Fragment f : fragments)
      {
        if ((f.getChildFragmentManager() != null) && (f.getChildFragmentManager().getBackStackEntryCount() > 0))
        {
          fmLast = f.getFragmentManager();
          FragmentManager fmChild = getLastFragmentManagerWithBack(f.getChildFragmentManager());
    
          if (fmChild != fmLast)
            fmLast = fmChild;
        }
      }
    
      return fmLast;
    }
    

    调用方法:

    @Override
    public void onBackPressed()
    {
      FragmentManager fm = getLastFragmentManagerWithBack(getSupportFragmentManager());
    
      if (fm.getBackStackEntryCount() > 0)
      {
        fm.popBackStack();
        return;
      }
    
      super.onBackPressed();
    }
    
  • 13

    超过5年,这个问题仍然有用 . 如果由于其限制而不想使用fragmentManager.getFragments() . 扩展并使用以下类:

    NestedFragmentActivity.java

    abstract public class NestedFragmentActivity extends AppCompatActivity {
    
        private final Stack<Integer> mActiveFragmentIdStack = new Stack<>();
        private final Stack<String> mActiveFragmentTagStack = new Stack<>();
    
        @Override
        public void onBackPressed() {
            if (mActiveFragmentIdStack.size() > 0 && mActiveFragmentTagStack.size() > 0) {
    
                // Find by id
                int lastFragmentId = mActiveFragmentIdStack.lastElement();
                NestedFragment nestedFragment = (NestedFragment) getSupportFragmentManager().findFragmentById(lastFragmentId);
    
                // If cannot find by id, find by tag
                if (nestedFragment == null) {
                    String lastFragmentTag = mActiveFragmentTagStack.lastElement();
                    nestedFragment = (NestedFragment) getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
                }
    
                if (nestedFragment != null) {
                    nestedFragment.onBackPressed();
                }
    
                // If cannot find by tag, then simply pop
                mActiveFragmentTagStack.pop();
                mActiveFragmentIdStack.pop();
    
            } else {
                super.onBackPressed();
            }
        }
    
        public void addToBackStack(int fragmentId, String fragmentTag) {
            mActiveFragmentIdStack.add(fragmentId);
            mActiveFragmentTagStack.add(fragmentTag);
        }
    }
    

    NestedFragment.java

    abstract public class NestedFragment extends Fragment {
    
        private final Stack<Integer> mActiveFragmentIdStack = new Stack<>();
        private final Stack<String> mActiveFragmentTagStack = new Stack<>();
    
        private NestedFragmentActivity mParentActivity;
        private NestedFragment mParentFragment;
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
    
            if (getParentFragment() == null) {
                try {
                    mParentActivity = (NestedFragmentActivity) context;
                } catch (ClassCastException e) {
                    throw new ClassCastException(context.toString()
                            + " must implement " + NestedFragmentActivity.class.getName());
                }
            } else {
                try {
                    mParentFragment = (NestedFragment) getParentFragment();
                } catch (ClassCastException e) {
                    throw new ClassCastException(getParentFragment().getClass().toString()
                            + " must implement " + NestedFragment.class.getName());
                }
            }
        }
    
        public void onBackPressed() {
    
            if (mActiveFragmentIdStack.size() > 0 && mActiveFragmentTagStack.size() > 0) {
    
                // Find by id
                int lastFragmentId = mActiveFragmentIdStack.lastElement();
                NestedFragment nestedFragment = (NestedFragment) getChildFragmentManager().findFragmentById(lastFragmentId);
    
                // If cannot find by id, find by tag
                if (nestedFragment == null) {
                    String lastFragmentTag = mActiveFragmentTagStack.lastElement();
                    nestedFragment = (NestedFragment) getChildFragmentManager().findFragmentByTag(lastFragmentTag);
                }
    
                if (nestedFragment != null) {
                    nestedFragment.onBackPressed();
                }
    
                // If cannot find by tag, then simply pop
                mActiveFragmentIdStack.pop();
                mActiveFragmentTagStack.pop();
    
            } else {
                getChildFragmentManager().popBackStack();
            }
        }
    
        private void addToBackStack(int fragmentId, String fragmentTag) {
            mActiveFragmentIdStack.add(fragmentId);
            mActiveFragmentTagStack.add(fragmentTag);
        }
    
        public void addToParentBackStack() {
            if (mParentFragment != null) {
                mParentFragment.addToBackStack(getId(), getTag());
            } else if (mParentActivity != null) {
                mParentActivity.addToBackStack(getId(), getTag());
            }
        }
    }
    

    Explanation:

    从上面的类扩展的每个活动和片段为他们的每个孩子和孩子的孩子管理他们自己的后台堆栈,依此类推 . backstack只是“活动片段”标签/ ID的记录 . 因此,需要注意的是始终为您的片段提供标记和/或ID .

    在childFragmentManager中添加到backstack时,您还需要调用“addToParentBackStack()” . 这确保了片段的标签/ id被添加到父片段/活动中以用于以后的弹出 .

    例:

    getChildFragmentManager().beginTransaction().replace(
                R.id.fragment,
                fragment,
                fragment.getTag()
        ).addToBackStack(null).commit();
        addToParentBackStack();
    
  • 54

    有了这个答案,它将处理递归反向检查,并为每个片段提供覆盖默认行为的机会 . 这意味着你可以拥有一个托管ViewPager的片段做一些特别的事情,比如滚动到作为后台的页面,或滚动到主页然后在下一个后退出口 .

    将此添加到扩展AppCompatActivity的Activity .

    @Override
    public void onBackPressed()
    {
        if(!BaseFragment.handleBackPressed(getSupportFragmentManager())){
            super.onBackPressed();
        }
    }
    

    将此添加到您的BaseFragment或您可以让所有片段继承的类 .

    public static boolean handleBackPressed(FragmentManager fm)
    {
        if(fm.getFragments() != null){
            for(Fragment frag : fm.getFragments()){
                if(frag != null && frag.isVisible() && frag instanceof BaseFragment){
                    if(((BaseFragment)frag).onBackPressed()){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    protected boolean onBackPressed()
    {
        FragmentManager fm = getChildFragmentManager();
        if(handleBackPressed(fm)){
            return true;
        }
        else if(getUserVisibleHint() && fm.getBackStackEntryCount() > 0){
            fm.popBackStack();
            return true;
        }
        return false;
    }
    
  • 43

    原因是您的Activity派生自FragmentActivity,它处理BACK键按下(参见FragmentActivity的第173行) .

    在我们的应用程序中,我使用的是ViewPager(带有片段),每个片段都可以嵌套片段 . 我处理这个问题的方法是:

    • 使用单个方法定义接口OnBackKeyPressedListener void onBackKeyPressed()

    • 在ViewPager显示的"top"片段中实现了此接口

    • 重写onKeyDown并检测BACK按,并在视图寻呼机中的当前活动片段中调用onBackKeyPressed .

    另请注意,我在片段中使用 getChildFragmentManager() 来正确嵌套片段 . 您可以在this android-developers post中查看讨论和解释 .

  • 21

    这个问题的真正答案是在Fragment Transaction的函数setPrimaryNavigationFragment中 .

    /**
     * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
     *
     * <p>The primary navigation fragment's
     * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
     * to process delegated navigation actions such as {@link FragmentManager#popBackStack()}
     * if no ID or transaction name is provided to pop to. Navigation operations outside of the
     * fragment system may choose to delegate those actions to the primary navigation fragment
     * as returned by {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
     *
     * <p>The fragment provided must currently be added to the FragmentManager to be set as
     * a primary navigation fragment, or previously added as part of this transaction.</p>
     *
     * @param fragment the fragment to set as the primary navigation fragment
     * @return the same FragmentTransaction instance
     */
    public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);
    

    您必须在活动添加时在初始父片段上设置此功能 . 我的活动中有一个replaceFragment函数,如下所示:

    public void replaceFragment(int containerId, BaseFragment fragment, boolean addToBackstack) {
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.setPrimaryNavigationFragment(fragment);
        if (addToBackstack) {
            fragmentTransaction.addToBackStack(fragment.TAG);
        }
    
        fragmentTransaction.replace(containerId, fragment).commit();
    }
    

    这会给你一样的行为,就像你从常规片段B回到片段A一样,除了现在它也在子片段上!

  • -1

    如果你有 DialogFragment 又有嵌套片段,'workaround'有点不同 . 而不是将 onKeyListener 设置为 rootView ,而是需要使用 Dialog 来执行此操作 . 你也将设置 DialogInterface.OnKeyListener 而不是 View . 当然,记得 addToBackStack

    顺便说一句,在Backstack上有1个片段用于将呼叫委托给活动是我的个人用例 . 典型情况可能是计数为0 .

    这是你在onCreateDialog中要做的事情

    @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Dialog dialog =  super.onCreateDialog(savedInstanceState);
            dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    if(keyCode == KeyEvent.KEYCODE_BACK){
                        FragmentManager cfm = getChildFragmentManager();
                        if(cfm.getBackStackEntryCount()>1){
                            cfm.popBackStack();
                            return true;
                        }   
                    }   
                    return false;
                }
            });
            return dialog;
        }
    
  • 2

    通过在onCreate View()方法中向父片段添加此方法并传递根视图,我能够处理片段后端堆栈 .

    private void catchBackEvent(View v){
        v.setFocusableInTouchMode(true);
        v.requestFocus();
        v.setOnKeyListener( new OnKeyListener()
        {
            @Override
            public boolean onKey( View v, int keyCode, KeyEvent event )
            {
                if( keyCode == KeyEvent.KEYCODE_BACK )
                {
                    if(isEnableFragmentBackStack()){
                        getChildFragmentManager().popBackStack();
                                        setEnableFragmentBackStack(false);
                        return true;
                    }
                    else
                        return false;   
                }
                return false;
            }
        } );
    }
    

    方法isEnableFragmentBackStack()是一个布尔标志,用于知道我何时在主片段或下一个片段上 .

    确保在提交需要堆栈的片段时,必须添加addToBackstack方法 .

  • 1

    好像是个bug . 看看:http://code.google.com/p/android/issues/detail?id=40323

    对于我已成功使用的解决方法(如评论中所示):

    @Override
    public void onBackPressed() {
    
        // If the fragment exists and has some back-stack entry
        if (mActivityDirectFragment != null && mActivityDirectFragment.getChildFragmentManager().getBackStackEntryCount() > 0){
            // Get the fragment fragment manager - and pop the backstack
            mActivityDirectFragment.getChildFragmentManager().popBackStack();
        }
        // Else, nothing in the direct fragment back stack
        else{
            // Let super handle the back press
            super.onBackPressed();          
        }
    }
    
  • -1

    这个解决方案可能更好,因为它会检查所有嵌套片段的级别:

    /**
     * This method will go check all the back stacks of the added fragments and their nested fragments
     * to the the {@code FragmentManager} passed as parameter.
     * If there is a fragment and the back stack of this fragment is not empty,
     * then emulate 'onBackPressed' behaviour, because in default, it is not working.
     *
     * @param fm the fragment manager to which we will try to dispatch the back pressed event.
     * @return {@code true} if the onBackPressed event was consumed by a child fragment, otherwise {@code false}.
     */
    public static boolean dispatchOnBackPressedToFragments(FragmentManager fm) {
    
        List<Fragment> fragments = fm.getFragments();
        boolean result;
        if (fragments != null && !fragments.isEmpty()) {
            for (Fragment frag : fragments) {
                if (frag != null && frag.isAdded() && frag.getChildFragmentManager() != null) {
                    // go to the next level of child fragments.
                    result = dispatchOnBackPressedToFragments(frag.getChildFragmentManager());
                    if (result) return true;
                }
            }
        }
    
        // if the back stack is not empty then we pop the last transaction.
        if (fm.getBackStackEntryCount() > 0) {
            fm.popBackStack();
            fm.executePendingTransactions();
            return true;
        }
    
        return false;
    }
    

    在您的活动 onBackPressed 中,您可以这样简单地调用它:

    FragmentManager fm = getSupportFragmentManager();
                    // if there is a fragment and the back stack of this fragment is not empty,
                    // then emulate 'onBackPressed' behaviour, because in default, it is not working
                    if (!dispatchOnBackPressedToFragments(fm)) {
                        // if no child fragment consumed the onBackPressed event,
                        // we execute the default behaviour.
                        super.onBackPressed();
                    }
    
  • 3

    感谢大家的帮助,这个(调整后的版本)适合我:

    @Override
    public void onBackPressed() {
        if (!recursivePopBackStack(getSupportFragmentManager())) {
            super.onBackPressed();
        }
    }
    
    /**
     * Recursively look through nested fragments for a backstack entry to pop
     * @return: true if a pop was performed
     */
    public static boolean recursivePopBackStack(FragmentManager fragmentManager) {
        if (fragmentManager.getFragments() != null) {
            for (Fragment fragment : fragmentManager.getFragments()) {
                if (fragment != null && fragment.isVisible()) {
                    boolean popped = recursivePopBackStack(fragment.getChildFragmentManager());
                    if (popped) {
                        return true;
                    }
                }
            }
        }
    
        if (fragmentManager.getBackStackEntryCount() > 0) {
            fragmentManager.popBackStack();
            return true;
        }
    
        return false;
    }
    

    注意:你会的可能还想将这些嵌套片段的背景颜色设置为应用主题的窗口背景颜色,因为默认情况下它们是透明的 . 有点超出了这个问题的范围,但它是通过解析属性android.R.attr.windowBackground,并将Fragment视图的背景设置为该资源ID来实现的 .

  • 1

    对于ChildFragments,这工作..

    @Override
        public void onBackPressed() {
    
     if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                getSupportFragmentManager().popBackStack();
            } else {
                doExit(); //super.onBackPressed();
            }
    }
    
  • 1

    这个解决方案可能是@Sean答案的更好版本:

    @Override
    public void onBackPressed() {
        // if there is a fragment and the back stack of this fragment is not empty,
        // then emulate 'onBackPressed' behaviour, because in default, it is not working
        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
            }
        }
        super.onBackPressed();
    }
    

    我再次根据上面的@Sean回答准备了这个解决方案 .

    正如@ AZ13所说,这个解决方案只适用于一级子片段情况 . 在多级碎片的情况下,工作变得有点复杂,所以我建议尝试这个解决方案只是我所说的可行案例 . =)

    Note: 由于 getFragments 方法现在是私有方法,因此该解决方案不起作用 . 您可以检查链接的注释,该链接建议有关此情况的解决方案 .

  • 2

    这个解决方案可能是@msms答案的更好版本:

    嵌套片段版本

    private boolean onBackPressed(FragmentManager fm) {
        if (fm != null) {
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStack();
                return true;
            }
    
            List<Fragment> fragList = fm.getFragments();
            if (fragList != null && fragList.size() > 0) {
                for (Fragment frag : fragList) {
                    if (frag == null) {
                        continue;
                    }
                    if (frag.isVisible()) {
                        if (onBackPressed(frag.getChildFragmentManager())) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    @Override
    public void onBackPressed() {
        FragmentManager fm = getSupportFragmentManager();
        if (onBackPressed(fm)) {
            return;
        }
        super.onBackPressed();
    }
    

相关问题