With Android 4.2, the support library got support for nested fragments see here. I've played around with it and found an interesting behaviour / bug regarding back stack and getChildFragmentManager(). When using getChildFragmentManager() and addToBackStack(String name), by pressing the back button the system does not run down the back stack to the previous fragment. On the other hand, when using getFragmentManager() and addToBackStack(String name), by pressing the back button the system returns to the previous fragment.
For me, this behaviour is unexpected. By pressing the back button on my device, I'm expecting that the last added fragment to the back stack will be popped, even if the fragment was added to the back stack in the children's fragment manager.
Is this behaviour correct? Is this behaviour a bug? Is there a work around for this issue?
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); } } }
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); } } }
This solution may be better version of @Sean answer:
@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(); }
Again, I prepared this solution based on @Sean answer above.
As @AZ13 said, this solution is only feasible in one level child fragments situations. In multiple level fragments case, works become a little complex, so I recommend that try this solution only the feasible case I have said. =)
Note: Since getFragments
method is now a private method, this solution will not work. You can check comments for a link which suggests a solution about this situation.
Seems like a bug. Take a look at: http://code.google.com/p/android/issues/detail?id=40323
For a workaround I've used successfully (as suggested in comments):
@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(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With