4

I am having issues with nested/child fragments. My use case is: I have Frag A as parent fragment and FragChild1, FragChild2, FragChild3 as child fragments to be displayed inside Frag A. Now on back press from FragChild3 it should work like :

FragChild3 -> FragChild2 -> FragChild1 -> FragA(ParentFrag).

The code I used to add child fragments are-

for ChildFrag1-

Fragment mChildFragment1 = new ChildFragment1();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.replace(R.id.container_view, mChildFragment1);
        transaction.addToBackStack("FragChild1");
        transaction.commit();
        
for ChildFrag2-

Fragment mChildFragment2 = new ChildFragment2();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.replace(R.id.container_view, mChildFragment2);
        transaction.addToBackStack("FragChild2");
        transaction.commit();

I have searched through StackOverflow for relevant answers but haven't yet found any proper answer/way of managing backstack for child fragments.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Bella
  • 99
  • 1
  • 8
  • Is fragment 3 a child of fragment 2 and fragment 2 a child of fragment 1? – Jordan Aug 28 '18 at 07:35
  • How are you displaying 1,2 and 3? Are you using a view pager? – Jordan Aug 28 '18 at 07:36
  • No i am not using viewpager. Though i want the behaviour of child1,2,3 as viewpager only. And child1,2,3 are independent of each other . All 3 have parent as frag A and the child frags are placed in the same container – Bella Aug 28 '18 at 07:43
  • I want a viewpager behaviour with the child frags but i am using getChildFragmentMaager() – Bella Aug 28 '18 at 07:43
  • You actually need to override onBackPressed() event in your activity that hosts all these fragments and have to check manually which fragment is on top of the stack each time the back button is pressed. – Jordan Aug 28 '18 at 07:48
  • Also 1,2 and 3 won't be independent exactly. They won't have parent-child relationship. However, there must be an order of visibility as per your requirement. If you want to go back as 3,2,1 then you also have to come forward as 1,2,3. – Jordan Aug 28 '18 at 07:52
  • Right the order of visibility is 1,2,3 and their parent is not an activity but a fragment. I tried overriding backPressed which didn't work. That is my question exactly how to achieve this – Bella Aug 28 '18 at 08:02
  • @Override public void onBackPressed() { FragmentManager fm = getSupportFragmentManager(); for (Fragment frag : fm.getFragments()) { if (frag.isVisible()) { FragmentManager childFm = frag.getChildFragmentManager(); if (childFm.getBackStackEntryCount() > 0) { childFm.popBackStack(); return; } } } super.onBackPressed(); } – Bella Aug 28 '18 at 08:03
  • I used the above code for popping child fragments – Bella Aug 28 '18 at 08:03
  • Why not let the `ViewPager` deal with this kind of behaviour ? – Greggz Aug 28 '18 at 08:05
  • okay so the code that you are using to pop the fragments will actually start working if you add() fragments instead of replacing them. – Jordan Aug 28 '18 at 08:16
  • Let the fragments overlap just manage the transition manually. – Jordan Aug 28 '18 at 08:18
  • check out the code available in [this](https://stackoverflow.com/questions/13418436/android-4-2-back-stack-behaviour-with-nested-fragments) post as well – Jordan Aug 28 '18 at 08:20
  • Does this answer your question? [Android 4.2: back stack behaviour with nested fragments](https://stackoverflow.com/questions/13418436/android-4-2-back-stack-behaviour-with-nested-fragments) – Daniil Pavlenko Jul 09 '21 at 07:14

4 Answers4

4

Your code seems good. Just override onbackpressed method in activity that contains parent fragment and put given code in it.

if (parentfragment.getChildFragmentManager().getBackStackEntryCount() > 1) {
    parentfragment.getChildFragmentManager().popBackStackImmediate();
} else {
    super.onBackPressed();
}
Amninder Singh
  • 321
  • 1
  • 10
1

Now this behavior can be implemented with OnBackPressedDispatcher without overriding onBackPressed in an Activity.

In your parent fragment (where your fragment container is located) add this code in onAttach method:

override fun onAttach(context: Context) {
    super.onAttach(context)
    val backCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // Remove all fragments from the childFragmentManager,
            // but exclude the first added child fragment.
            // This child fragment will be deleted with its parent.
            if (childFragmentManager.backStackEntryCount > 1) {
                childFragmentManager.popBackStack()
                return
            }
            // Delete parent fragment
            parentFragmentManager.popBackStack()
        }
    }
    requireActivity().onBackPressedDispatcher.addCallback(this, backCallback)
}

Than add fragments in your container like this:

childFragmentManager.commit {
    replace(R.id.fragmentContainerRoot, fragment)
    addToBackStack(null)
}
Daniil Pavlenko
  • 153
  • 1
  • 9
0

Pass the tag into the replace method. TAG can as simple as the fragments name (String). Change your code like this:

transaction.replace(R.id.container_view, mChildFragment1, "FragChild1");
transaction.addToBackStack("FragChild1");
transaction.commit();
Prashanth Verma
  • 588
  • 3
  • 11
  • how would that help? – Bella Aug 28 '18 at 07:45
  • Did you try add() instead of replace(). Because replace clears everything and adds your new fragment. And you need to override onbackpressed() if you use replace() along with addtoBackStack(). – Prashanth Verma Aug 28 '18 at 07:53
  • If I add instead of replace then the child fragments are overlapping .I am placing the child frags in the single container of parent – Bella Aug 28 '18 at 07:55
  • How to achieve the behaviour of popping each child fragment overriding onbackpressed ? – Bella Aug 28 '18 at 07:56
  • I would suggest, put all your logic in activity which means opening of the fragments should be in the activity, you shouldn't open Fragment B from Fragment A, instead tell activity that Fragment B should be opened (using interface). Now override the onbackpressed of activity NOT fragment's – Prashanth Verma Aug 28 '18 at 07:59
0

Try This,

Fragment fragment= new ChildFragment1();
getChildFragmentManager().beginTransaction().replace(R.id.contentView, fragment).addToBackStack(fragment.getClass().getName()).commitAllowingStateLoss();
SHIDHIN TS
  • 1,557
  • 3
  • 26
  • 58