I have an app project where there is 10 Fragments. When user open a Fragment I want to in code know this and save the Fragment as the last Fragment user has visited.
If user close app and open it again this last visited Fragment will be showed to user.
I read many answers about this and there does not seam to be a consensus on a solution to know what Fragment is currently visible for User.
I was thinking to subclass FragmentManager maybe to detect popping and monitor queue state.
Or maybe put some GestureDetector.OnGestureListener in the Fragment and when that fires I can save the last Fragment user has visited.
Any help on this would be grate
This is what happen when user in the Fragment press back press button
/**
* user press back button
*/
#Override
public void onBackPressed() {
//Fragment fragment = getVisibleFragment();
//get the name from the topmost BackStackEntry which is also the fragment tag.
String fragmentTag = mFragManager.getBackStackEntryAt(mFragManager.getBackStackEntryCount()-1).getName();
Fragment currentFrag = mFragManager.findFragmentByTag(fragmentTag);
if (currentFrag == null ) {
super.onBackPressed();
}
if (currentFrag != null) {
if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.CHAT_FRAGMENT.toString())) {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
openDrawer(false);
} else
requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.BILLBOARD_FRAGMENT.toString())) {
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.NEWS_FRAGMENT.toString())) {
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.INFO_FRAGMENT.toString())) {
super.onBackPressed();
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.SEARCH_FRAGMENT.toString())) {
// exit app if the search address view is visible
if (currentFrag.getView().findViewById(R.id.search_address_layout).getVisibility() == View.VISIBLE) {
exitApp();
} else if (currentFrag.getView().findViewById(R.id.show_search_result_layout).getVisibility() == View.VISIBLE) {
// show search address view if Address already exist view is visible
currentFrag.getView().findViewById(R.id.search_address_layout).setVisibility(View.VISIBLE);
currentFrag.getView().findViewById(R.id.history).setVisibility(View.VISIBLE);
currentFrag.getView().findViewById(R.id.show_search_result_layout).setVisibility(View.INVISIBLE);
((SearchFragment)currentFrag).onSearchLayoutVisible();
}
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT.toString())) {
super.onBackPressed();
//requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT_CHAT_SETTINGS.toString())) {
super.onBackPressed();
//requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.PREFERENCE_FRAGMENT_THEME_SETTINGS.toString())) {
super.onBackPressed();
//requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
} else if (currentFrag.getTag().equals(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString())) {
super.onBackPressed();
//requestBeginTransaction(SettingsManager.FragmentsModel.LAUNCHER_FRAGMENT.toString(), true, false);
}
} else
exitApp();
}
In the code above i pop Fragment and dont know what Fragment is under the popt Fragment.
Here is when I add or show Fragment
/**
* Change the current displayed fragment by a new one.
* - if the fragment is in backstack, it will pop it
* - if the fragment is already displayed (trying to change the fragment with the same), it will not do anything
*
* #param backStateName the new fragment to display
* #param saveInBackstack if we want the fragment to be in backstack
* #param animate if we want a nice animation or not
*/
public void requestBeginTransaction(String backStateName, boolean saveInBackstack, boolean animate) {
Fragment frag = null;
if (mFragManager.findFragmentByTag(backStateName) != null) {
frag = mFragManager.findFragmentByTag(backStateName);
} else
try {
frag = (Fragment) Class.forName(backStateName).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
//fragment not in back stack, create it.
FragmentTransaction transaction = manager.beginTransaction();
if (animate) {
LogManager.d(this, "Change Fragment: animate");
// transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
}
transaction.add(R.id.frame, frag, backStateName);
if (saveInBackstack) {
LogManager.d(this, "Change Fragment: addToBackTack " + backStateName);
transaction.addToBackStack(backStateName);
LogManager.d(this, "Change Fragment: NO addToBackTack");
}
transaction.commit();
} else {
mFragManager.beginTransaction().show(mFragManager.findFragmentByTag(backStateName)).commit();
// custom effect if fragment is already instanciated
}
} catch (IllegalStateException exception) {
LogManager.w(this, "Unable to commit fragment, could be activity as been killed in background. " + exception.toString());
}
}
You can test it by looking at its instance.
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceOf Fragment1) {
// It is fragment of class Fragment1
} else if (fragment instanceOf Fragment2) {
// It is fragment of class Fragment2
}
When the user presses back button, have this in your activity (not fragment):
#Override
public void onBackPressed() {
super.onBackPressed();
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceOf Fragment1) {
// It is fragment of class Fragment1
} else if (fragment instanceOf Fragment2) {
// It is fragment of class Fragment2
}
// Save to prefs which fragment tag it is
}
If you only need to know the last visible fragment to restore it if the user closes the app, I would suggest to simply store the fragment's tag (or some identifier) in the SharedPreferences when it's started. Then, you can use that preference value later to set the correct fragment when the application starts.
You can do that by overriding the onStart() fragment method.
Related
I have bottom navigation and set each item load a fragment. When my application load Home fragment default selected. My application fragment Backstack work when navigate for example click Posts > Search > Favor and after press back it's work and back to Search > Post > Home But my problem in select again Previous fragment for example when navigate Post > Search > Post now when press back first press not working and not back any fragment and second press back to Home. I want work this format when navigate Post > Search > Post on press back navigate Search > Home.
I have pushFragments method and Override onBackPressed. My codes this is:
pushFragments method:
public void pushFragments(String tag, Fragment fragment){
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction fTransaction = manager.beginTransaction();
if (manager.findFragmentByTag(tag)==null){
fTransaction.add(R.id.frame_fragmentMain_container,fragment,tag);
fTransaction.addToBackStack(tag);
}
Fragment homeFragment = manager.findFragmentByTag(TAG_FRAGMENT_HOME);
Fragment postsFragment = manager.findFragmentByTag(TAG_FRAGMENT_POSTS);
Fragment usersFragment = manager.findFragmentByTag(TAG_FRAGMENT_USERS);
Fragment searchFragment = manager.findFragmentByTag(TAG_FRAGMENT_SEARCH);
Fragment favorFragment = manager.findFragmentByTag(TAG_FRAGMENT_FAVOR);
// Hide all Fragment
if(homeFragment!=null){
fTransaction.hide(homeFragment);
}
if(postsFragment!=null){
fTransaction.hide(postsFragment);
}
if(usersFragment!=null){
fTransaction.hide(usersFragment);
}
if(searchFragment!=null){
fTransaction.hide(searchFragment);
}
if(favorFragment!=null){
fTransaction.hide(favorFragment);
}
switch (tag){
case TAG_FRAGMENT_HOME:
if(homeFragment!=null){
fTransaction.show(homeFragment);
setToolbarTitle("Home Page");
disableNavigationToolbarIcon();
}
break;
case TAG_FRAGMENT_POSTS:
if(postsFragment!=null){
fTransaction.show(postsFragment);
setToolbarTitle("Posts List");
enabledNavigationToolbarIcon();
}
break;
case TAG_FRAGMENT_USERS:
if(usersFragment!=null){
fTransaction.show(usersFragment);
setToolbarTitle("Authors List");
enabledNavigationToolbarIcon();
}
break;
case TAG_FRAGMENT_SEARCH:
if(searchFragment!=null){
fTransaction.show(searchFragment);
setToolbarTitle("Search Page");
enabledNavigationToolbarIcon();
}
break;
case TAG_FRAGMENT_FAVOR:
if(favorFragment!=null){
fTransaction.show(favorFragment);
setToolbarTitle("Favor Posts");
enabledNavigationToolbarIcon();
}
break;
}
fTransaction.commitAllowingStateLoss();
}
and Override onBackPressed:
#Override
public void onBackPressed() {
FragmentManager manager = getSupportFragmentManager();
if(manager.getBackStackEntryCount()>1){
for (Fragment fragment : manager.getFragments()){
if(fragment.isVisible()){
FragmentManager childManager = fragment.getChildFragmentManager();
if(childManager.getBackStackEntryCount()>0){
if(fragment instanceof UsersFragment){
setToolbarTitle("Authors List");
}
childManager.popBackStack();
return;
}
}
}
manager.popBackStack();
}else{
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
finish();
moveTaskToBack(true);
}
}).create().show();
}
}
Try this out..It will definitely work..
public void pushFragments(Fragment fragment) {
try {
String backStateName = fragment.getClass().getName();
FragmentManager fragmentManager = getSupportFragmentManager();
boolean fragmentPop = fragmentManager.popBackStackImmediate(backStateName, 0);
if (!fragmentPop) {
try {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.addToBackStack(backStateName);
fragmentTransaction.commit();
} catch (Exception e) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
and in OnBackPress ---
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
finish();
return;
}
super.onBackPressed();
}
I have a DrawerMenuActivity suppose "AA" and it has 3 fragments "A", "B" and "C" as it's menu. Fragment "A" is my default screen. Now i have navigated to the fragment "B" which has listview items and each item click will open another new activity "AB". In AB there will be a button and that button click will open another activity "AC". so Basically the flow is as follows,
From AA(DrawerMenuActivity) -> "A" fragemnt -> "B" or "C" fragments -> AB(Activity) -> AC(Activity)
Now what i want to do is to return to fragment "B" from the Activity "AC".
I have replaced the fragments of Activity "AA" like this,
in OnCreate(),
if (savedInstanceState == null) {
A fragment = new A();
replaceFragment(fragment, false, Constants.HOME_FRG_TAG);
Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
if (getIntent().getStringExtra("FROM AC") != null) {
updateDisplay(1);
}
}
};
handler.postDelayed(runnable, 10);
}
and for replacing fragments,
public void updateDisplay(int position) {
Fragment fragment = null;
String tag = null;
switch (position) {
case 0:
clearStack();
mDrawerLayout.closeDrawer(mDrawerList);
break;
case 1:
fragment = new B();
tag = "B";
break;
case 2:
fragment = new C();
tag = "C";
break;
default:
break;
}
if (fragment != null) {
replaceFragment(fragment, true, tag);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
Log.e("Activity", "Error in creating fragment");
}
}
replaceFragment() function,
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
if (backStackTag) transaction.addToBackStack(null);
transaction.commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
and clearStack(),
public void clearStack() {
FragmentManager fm = AA.this.getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
in AC Activity i have tried to come back to fragment "B" like this,
Intent in = new Intent(AC.this, AA.class);
in.putExtra("FROM AC", "from ac");
startActivity(in);
now this does what i intend to do but the problem is when it is loading fragment "A" opens for a brief time and then it comes back to the fragment "B".
How Do i navigate to fragment "B" from Activity "AC" properly?? please any help would be appreciated...!!
First when you go from AB to AC start it as with startActvityForResult, and make sure you don't pass the clear backstack flags. Do it just like this:
public static final int REQ_CODE = 1;
Intent in = new Intent(this, AB.class);
startActivityForResult(in, REQ_CODE);
So the backstack is not cleared. When replacing the fragments in AA do it like this:
public void replaceFragment(Fragment newFragment, boolean backStackTag, String fragmentTag) {
try {
Fragment selectedFrag = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (selectedFrag != null && selectedFrag.isVisible()) {
return;
}
FragmentManager fm = AA.this.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.container, fragmentB).commit();
} catch (Exception e) {
Log.e("exception ", " on adding fragment");
// TODO: handle exception
}
}
And when you want to get back from activity AC, set the result to RESULT_OK if you want to navigate back to AA or RESULT_CANCELED if not.
setResult(Activity.RESULT_OK);
finish();
In AB, override the onActivityResult method so it sends you back to AA:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQ_CODE) {
if (resultCode == RESULT_OK) {
finish();
}
}
}
so if RESULT_OK is passed, it will go back to AA where the activity was still in onStop() and the state was saved. Also make sure to init your views in onCreate and not in onStart.
Use startActivityForResult to pass params from AC to AA.It's a little complicated.EventBus may be helpful to you.
I have an "activity A" that launches two fragments, with the home button being part of the activity A, and when the back button is pressed from the createFragment it should go back to the activity before activity A, which it does fine with the finish() method but when I have the second fragment, followersFragment which is added ontop of createFragment and hides createFragment (because I do not want the information being lost in the create), then I hit the back button and it switches back to the create fragment but then when I hit the back button from createFragment it does not go back to activity A anymore and does nothing... no error...
This is my code on the activity that holds the fragments(not activity A):
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
// lets user travel back to where they came from
case android.R.id.home:
if(displayShown == 1) {
displayView(2, 0);
} else {
}
return true;
private void displayView(int i, int position) {
Log.d(Constants.DEBUG, "display view called " +position);
boolean createPost = true;
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
//avoid recreating createPostFragment if already created because all data will be erased
if(createPostFragment == null){
createPost = false;
Log.d(Constants.DEBUG, "fragment create DOES NOT EXIST ");
createPostFragment = new CreatePostFragment();
}
fragment = createPostFragment;
break;
case 1:
followerFragment = new FollowerFragment();
fragment = followerFragment;
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
trans = fragmentManager.beginTransaction();
//if createpostfrag already created just show
if (createPost && position == 0) {
trans.remove(followerFragment);
trans.show(createPostFragment);
trans.commit();
//hide createpostfrag so we can reuse
} else {
if(position == 1) {
Bundle extraData = new Bundle();
extraData.putInt("follow", i);
fragment.setArguments(extraData);
trans.add(R.id.frame_container, fragment, null).commit();
trans.hide(createPostFragment);
}
if(position == 0) {
trans.add(R.id.frame_container, fragment, "keepAlive").commit();
}
}
} else {
// error in creating fragment
Log.d(Constants.DEBUG, "Error in creating fragment or no fragment needed");
}
}
Hee Guys,
I'm currently working with fragments and I'm trying to manage it so that when you click twice on the same menu item it won't put 2 of the same fragments on top of eachother. However it still does. Could anyone tell me what I'm doing wrong?
/*
* Method to check which action is behind the selected Menu item. Then call ShowFragment()
* With the correct fragment parameter used with this Menu action value.
*/
public void getAction(int position, Cursor cursor) {
// TODO Auto-generated method stub
mCursor = cursor;
cursor.moveToPosition(position);
String action = cursor.getString(cursor.getColumnIndex(AppMenu.ACTION));
if (action != null) {
if (action.equalsIgnoreCase("home")) {
trans = manager.beginTransaction();
BaseFragment newFragment = new HomeFragment();
if (manager.findFragmentByTag(newFragment.getTag()) != null) {
mCursor.moveToPosition(position);
// Set the current fragment
mCurrentFragment = newFragment;
Bundle bundle = new Bundle();
int fragId = mCursor.getInt(mCursor.getColumnIndex(AppMenu._ID));
Log.i(TAG, fragId + " ");
bundle.putInt("fragmentID", fragId);
newFragment.setArguments(bundle);
trans.replace(R.id.fragmentContainer, newFragment).addToBackStack(
newFragment.tag());
trans.commit();
} else {
trans.show(newFragment);
}
} else if (action.equalsIgnoreCase("event")) {
showFragment(new EventsFragment(), position);
} else if (action.equalsIgnoreCase("location")) {
showFragment(new LocationsFragment(), position);
} else if (action.equalsIgnoreCase("news")) {
showFragment(new NewsFragment(), position);
} else if (action.equalsIgnoreCase("bars")) {
showFragment(new BarsFragment(), position);
} else if (action.equalsIgnoreCase("currency")) {
showFragment(new CurrencyFragment(), position);
} else if (action.equalsIgnoreCase("map")) {
showFragment(new MapFragment(), position);
}
} else {
Log.i(TAG, "You've got a nullpointerexception on getAction().");
}
}
/*
* Method that's called when changing from fragment through Menu or HomeMenu.
*/
public void showFragment(BaseFragment newFragment, int position) {
trans = manager.beginTransaction();
if (manager.findFragmentByTag(newFragment.tag()) == null) {
mCursor.moveToPosition(position);
// Set the current fragment
mCurrentFragment = newFragment;
// Go on and set the bundle values and pass it on the fragment.
Bundle bundle = new Bundle();
int fragId = mCursor.getInt(mCursor.getColumnIndex(AppMenu._ID));
Log.i(TAG, fragId + " ");
bundle.putInt("fragmentID", fragId);
newFragment.setArguments(bundle);
trans.replace(R.id.fragmentContainer, newFragment).addToBackStack(
newFragment.tag());
trans.commit();
} else {
trans.show(newFragment);
}
}
And here are 2 callbacks for when something changes or when back pressed.
/*
* Interface method called whenever a new fragment is created.
*/
#Override
public void onNewFragment(BaseFragment newFragment) {
// TODO Auto-generated method stub
FragmentManager fm = getSupportFragmentManager();
Class<? extends Fragment> newFragmentClass = newFragment.getClass();
if (newFragmentClass == EventsFragment.class
|| newFragmentClass == LocationsFragment.class
|| newFragmentClass == MapFragment.class
|| newFragmentClass == NewsFragment.class
|| newFragmentClass == CurrencyFragment.class
|| newFragmentClass == BarsFragment.class) {
for (Fragment fragment : fm.getFragments()) {
if (fragment != null && ((Object) fragment).getClass() == newFragmentClass) {
while (((Object) mCurrentFragment).getClass() != newFragmentClass) {
popFragment();
}
popFragment();
break;
}
}
}
}
/*
* Interface method called when you navigate back from a fragment.
* Checks which fragment is active, calls upon this fragments back function to clear any data,
* then pops the first fragment on the backstack.
*/
#Override
public void onBackNavigated() {
// TODO Auto-generated method stub
if ((mCurrentFragment instanceof HomeFragment)
&& !((HomeFragment) mCurrentFragment)
.isStackEmpty()) {
System.exit(0);
// break;
}
if ((mCurrentFragment instanceof LocationsFragment)
&& !((LocationsFragment) mCurrentFragment)
.isStackEmpty()) {
((LocationsFragment) mCurrentFragment).goBack();
// return;
}
if ((mCurrentFragment instanceof EventsFragment)
&& !((EventsFragment) mCurrentFragment)
.isStackEmpty()) {
((EventsFragment) mCurrentFragment).goBack();
// return;
}
if ((mCurrentFragment instanceof MapFragment)
&& !((MapFragment) mCurrentFragment).isStackEmpty()) {
((MapFragment) mCurrentFragment).goBack();
// break;
}
if ((mCurrentFragment instanceof BarsFragment)
&& !((BarsFragment) mCurrentFragment).isStackEmpty()) {
((BarsFragment) mCurrentFragment).goBack();
// break;
}
if ((mCurrentFragment instanceof CurrencyFragment)
&& !((CurrencyFragment) mCurrentFragment).isStackEmpty()) {
((CurrencyFragment) mCurrentFragment).goBack();
// break;
}
popFragment();
}
/*
* Pops the first fragment in the backstack. Then sets this as the new current fragment.
* If no fragment is in the backstack then finish() is called. Which will destroy the only fragment.
* Which in this case exits the application.
*/
public void popFragment() {
if (manager.getBackStackEntryCount() > 1) {
manager.popBackStack();
manager.executePendingTransactions();
ArrayList<Fragment> reversedFragments = new ArrayList<Fragment>(
manager.getFragments());
Collections.reverse(reversedFragments);
for (Fragment fragment : reversedFragments)
if (fragment != null) {
mCurrentFragment = (BaseFragment) fragment;
break;
}
} else {
finish();
}
}
**NOTE : ** The tag() functions calls a final String from the fragment itself with the same hardcoded tag everytime. So every fragment of the same class has the same tag. (Which should prevent double fragments, but it still doesn't)
Solution:
The tag() was returning null al the time. (Don't know why) So I changed the showFragment(fragment, tag, position) and hardcoded the tag in the mainactivity. Then used :
trans.replace(R.id.fragmentContainer, newFragment, tag);
//instead of
trans.replace(R.id.fragmentContainer, newFragment).addToStackBack(tag);
Don't forget to still add it to the backstack! Or else your back navigation won't work.
Just add an extra line: trans.addToBackStack(tag);
You can set the tag while adding/replacing the Fragment,
So you need to mention it as :
trans.replace(R.id.fragmentContainer, newFragment,tag);
Pass the tag value to the method according to the Fragment
showFragment(new EventsFragment(),tag, position);
Hope it will help you ツ
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();
}
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.
Reference: http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack(java.lang.String,%20int)
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();
}
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();
}
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();
}
}
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;
}
}
}
}
}