Reputation: 644
I have implemented Navigation Drawer which is a subclass of Activity. I have many fragments in my application. My question goes here
Imagine there are 3 fragments :
Fragment_1 : Fragment_2 : Fragment_3
When I start my application, Fragment_1 is loaded When I click on some components on Fragment_1, I'm navigated to Fragment_2 and so on..
So it's like
Fragment_1 > Fragment_2 > Fragment_3
When I press back key from Fragment_2, I'm navigated back to Fragment_1 But when I press back key from Fragment_3, I'm navigated back to Fragment_1 (instead of Fragment_2)
I want something like this in my application on Back Key press
Fragment_1 < Fragment_2 < Fragment_3
I have used Fragment, FragmentManager, FragmentTransaction as follows :
MyFragment fragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null)commit();
and I tried overriding onBackPressed() in my MainActivity :
@Override
public void onBackPressed() {
getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0)
super.onBackPressed();
}
Upvotes: 19
Views: 43554
Reputation: 2028
Here is working and tested code by me, This will help you
private static final int TIME_INTERVAL = 2000;
private long mBackPressed;
private void applyExit() {
if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
finish();
} else {
Toast.makeText(this,"Press Again to exit",Toast.LENGTH_LONG).show();
}
mBackPressed = System.currentTimeMillis();
}
@Override
public void onBackPressed() {
fm = getSupportFragmentManager();
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
if (fm.getFragments().size() <= 1) {
applyExit();
} else {
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
applyExit();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
} else {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return;
}
}
}
}
}
Upvotes: 0
Reputation: 2773
The tric is in FragmentManager#executePendingTransactions();
.
This is what I use for nested fragments as well...:
/**
* 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
*/
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;
}
and in my onBackPressed
:
if (!FragmentUtils.dispatchOnBackPressedToFragments(fm)) {
// if no child fragment consumed the onBackPressed event,
// we execute the default behaviour.
super.onBackPressed();
}
Upvotes: 2
Reputation: 31
Use this code on tab change in your main activity to clear the stack.
int count = getFragmentManager().getBackStackEntryCount();
if(count>0){
for (int i = 0; i <count; i++) {
getFragmentManager().popBackStack();
}
}
Then on Back pressed of your main activity do this
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onbackpressed();
}
else {
getFragmentManager().popBackStack();
}
}
Upvotes: 0
Reputation: 959
Update your Activity#onBackPressed()
method to:
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The reason your implementation doesn't work is because the method FragmentManager#popBackStack()
is asynchronous and does not happen right after it is called.
From the documentation:
This function is asynchronous -- it enqueues the request to pop, but the action will not be performed until the application returns to its event loop.
Upvotes: 36
Reputation: 4284
You have to implement your own backstack implementation as explained here
Separate Back Stack for each tab in Android using Fragments
You can call the popFragments() whenever you click the back button in a fragment and call pushFragments() whenever you navigate from one Fragment to other.
in Short,
public void onBackPressed()
{
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack();
}
Upvotes: 3