addToBackstack not working when replacing fragments - android

I am having an issue where I call addToBackStack on my fragment when replacing it, but when I press back to go back to that fragment, it doesn't go back, it just closes my app.
Fragment fragmentWebView = new MyWebView();
transaction.replace(R.id.content_frame, fragmentWebView);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
Am I doing anything wrong here? everything looks fine to me.

Try to add this code to your activity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
Watched here
Hope it helps

I'm not sure if it's related but you shouldn't create your fragment using new, see this post on StackOverflow

You should call addToBackStack(MyWebView.class.getName()); and it is recommended that you check if your fragment exist. The complet transaction could be something like this:
Fragment fragmentWebView = getFragmentManager().findFragmentByTag(MyWebView.class.getName());
if (fragmentWebView == null)
fragmentWebView = new MyWebView();
transaction.replace(R.id.content_frame, fragmentWebView, MyWebView.class.getName());
transaction.addToBackStack(MyWebView.class.getName());
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
Now, you can identify your fragment by a tag (MyWebView.class.getName()). Hope it helps you!!

Related

Navigating between two fragments on backpress

I am having trouble going back to previous fragment on backpress from current fragment.
I have Two fragments and i navigate to second fragment on click and when i try to click back from the second fragment, i want to go back to the previous fragment but instead the app exits on backpress. below is the code i am using..
Fragment1 calling second fragment
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
In second Fragment i have implemented an interface OnBackpress and over riding the below method
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() != 0) {
if(getFragmentManager().findFragmentByTag("UserActivity") != null){
Log.e("UserActivity",getFragmentManager().findFragmentByTag("UserActivity").toString());
getFragmentManager().popBackStack();
};
}
}
But on back press the app exits. Instead i want to go back to previous fragment. What mistake am i doing? please help. thanks
You need to add you first fragment to back stack properly, you are doing it wrong in your first part of the code.
Use the following code instead.
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.replace(android.R.id.content, frag, "UserActivity");
transaction.commit();
Also there is no need to add any code in your onBackPressed after above change.
First, you need to add your fragments to the backstack:
public static void addFragment(FragmentManager fragmentManager, Fragment fragment, int id){
fragmentManager.beginTransaction().add(id, fragment).addToBackStack(null).commit();
}
Then you need to override the onBackPressed, which is a method gets called whenever a user clicks the back button:
#Override
public void onBackPressed() {
super.onBackPressed();
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
button.setVisibility(View.VISIBLE);
}
}
please change to add() instead of replace() in your code..
UserFragment frag = new UserFragment()
FragmentTransaction transaction = getFragmentManager().beginTransaction();
frag.setArguments(bundle);
transaction.addToBackStack("UserActivity");
transaction.add(android.R.id.content, frag, "UserActivity").addToBackStack(null);
transaction.commit();
This will solve your problem.

Android - prevent to open previous fragment

guys.
This must be a silly question but i'm not managing to work this out. My scenario is: i have in my MainActivity a BottomNavigation which i navigate over three fragments. And my problem is that when the back button (from android bottom navigation toolbar) is pressed the previous fragment opens but i want the app to close. So my question is: how i manage to prevent the previous fragments to open?
PS: I know it has something to do with FragmentMananger back stack but i did not understand how to use it.
PS2: Sorry for bad english.
The fragments are on the backstack.
Edit:
Work with FragmentTransaction and use addToBackStack (null)
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Override the onBackPressed() method in your activity.
#Override
public void onBackPressed() {
finish(); //This would close the app
}
Word of caution. This would close the activity in all the cases when the user presses back. To avoid this perhaps you would like to create something like this:
#Override
public void onBackPressed() {
if(someCondition) {
finish(); //This would close the activity
}
else {
super.onBackPressed(); //Fallbacks to default Android implementation
}
}

Clicking back button after a Fragment transaction using addToBackStack does nothing

I want to be able to reverse a replace FragmentTransaction by using addToBackStack():
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
Fragment scheduleFragment = new ScheduleFragment();
fragmentTransaction.replace(R.id.content_container, scheduleFragment, "scheduleFragment");
fragmentTransaction.addToBackStack("scheduleFragment");
fragmentTransaction.commit();
but after that, clicking the back button does nothing.
From the doc and it's supposed to reverse the transaction.
What am I missing?
The right way to do this is using onBackPressed() method to catch that back event in your app, and then "pop" the backStack with popBackStack(). For example:
public void onBackPressed()
{
// Catch back action and pops from backstack
// (if you called previously to addToBackStack() in your transaction)
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
getSupportFragmentManager().popBackStack();
}
// Default action on back pressed
else super.onBackPressed();
}
PD: Sorry for the delay answering, but I just saw your question. Hope it helps!
Try fragmentTransaction.addToBackStack(null)
The parameter for addToBackStack() is an optional name for the back state, you do not use the tag in the replace() method which is just an optional tag for the fragment.
You can read more about this here.
I's been a while but I hope this will help someone.
fragmentTransaction.addToBackStack(null) won't work if you are extending AppCompatActivity. It works well in Activity. I couldn't find the reason.
I implemented my own Fragment stack:
public Fragment addFragmentToStack(Fragment fragment){
if(MyApplication.fragmentStack.size()>20){
MyApplication.fragmentStack.remove(0);
}
return MyApplication.fragmentStack.push(fragment);
}
public void onBackPressed() {
if (MyApplication.fragmentStack.size() > 0) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_container, MyApplication.fragmentStack.pop());
ft.commit();
}
else{
finish();
}
}

Android addToBackStack() with more than 2 fragments

I have a very strange error I can't figure out.
I have 1 main Fragment and many secondary fragments. A->(B,C,D,E,F) where Fragment A should always stack on backstack but fragments B,C,D,E should change in and out.
I use these lines of code to do this:
getFragmentManager().executePendingTransactions();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
MyFragment mListFragment = new MyFragment();
transaction.replace(R.id.listFragmentPlaceHold, mListFragment, FRAGMENT_TAG);
if(getFragmentManager().getBackStackEntryCount() == 0)
transaction.addToBackStack(null);
transaction.commit();
The problem is this, if I go from Fragment A to Fragment B and the hit back button everything works correctly. I can do this as many times as I like.
Then, when I go A->B then switch out B a few times, A->(B,C,D) and hit back, I am still good, I get back to A. But, when I have done the above, and then I try to do it again. I again go from A -> B (without restarting activity) and then switch out B to C, D and then hit back, Fragment A is no longer there and I get a Null Pointer Exception.
Could someone please help me out, this is driving me nuts.
I always use getFragmentManager().executePendingTransactions(); before I try to reference Fragment A.
Thank you!
So after reading this and this post, I realized that replace() calls remove() which should call the onDestroy() method for the Fragment, in my case Fragment A associated with the view, thus if i called replace(), there is no guarantee that Fragment A would still be there and would not be re-created. Therefore, I used detach() instead to solve the problem.
My understanding may be wrong...but this did fix the problem:
getFragmentManager().executePendingTransactions();
MyFragment1 mListFragment1 =
(MyFragment1) getFragmentManager().findFragmentByTag(MY_FRAG1);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
MyFragment mListFragment = new MyFragment();
transaction.replace(R.id.listFragmentPlaceHold, mListFragment, FRAGMENT_TAG);
if(getFragmentManager().getBackStackEntryCount() == 0){
transaction.detach(mListFragment1);
transaction.add(R.id.listFragmentPlaceHold, mListFragment, FRAGMENT_TAG);
transaction.addToBackStack(null);
}else{
transaction.replace(R.id.listFragmentPlaceHold, mListFragment, FRAGMENT_TAG);
}
transaction.commit();

Programmatically go back to the previous fragment in the backstack

Say I have an activity that has fragments added programmatically:
private void animateToFragment(Fragment newFragment, String tag) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();
}
What is the best way to return to the previous fragment that was visible?
I found Trigger back-button functionality on button click in Android but I'm thinking simulating a back key event isn't the right way to go about it (and I can't get it to work either):
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
Calling finish() just closes the activity which I'm not interested in.
Is there a better way to go about this?
Look at the getFragmentManager().popBackStack() methods (there are several to choose from)
http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()
To elaborate on the other answers provided, this is my solution (placed in an Activity):
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
When we are updating/add the fragments,
Should Include the .addToBackStack().
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
.addToBackStack(null)
.commit();
After that if we give the getFragments.popBackStackImmediate() will return true if we add/update the fragments, and move back to the current screen.
Android Navigation architecture component.
The following code works for me:
findNavController().popBackStack()
These answers does not work if i don't have addToBackStack() added to my fragment transaction but, you can use:
getActivity().onBackPressed();
from your any fragment to go back one step;
Add those line to your onBackPressed() Method. popBackStackImmediate() method will get you back to the previous fragment if you have any fragment on back stack
`
if(getFragmentManager().getBackStackEntryCount() > 0){
getFragmentManager().popBackStackImmediate();
}
else{
super.onBackPressed();
}
`
This solution works perfectly for bottom bar based fragment navigation when you want to close the app when back pressed in primary fragment.
On the other hand when you are opening the secondary fragment (fragment in fragment) which is defined as "DetailedPizza" in my code it will return the previous state of primary fragment. Cheers !
Inside activities on back pressed put this:
Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");
if (home instanceof FragmentDetailedPizza && home.isVisible()) {
if (getFragmentManager().getBackStackEntryCount() != 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
} else {
//Primary fragment
moveTaskToBack(true);
}
And launch the other fragment like this:
Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();
Kotlin Answer
First, call Fragment Manager.
After, to use onBackPressed()
method.
Coding in Android Studio 4.0 with Kotlin:
fragmentManager?.popBackStack()
Programmatically go back to the previous fragment using following code.
if ( getFragmentManager().getBackStackEntryCount() > 0)
{
getFragmentManager().popBackStack();
return;
}
super.onBackPressed();
To make that fragment come again, just add that fragment to backstack which you want to come on back pressed, Eg:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new LoginFragment();
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack("SignupFragment");
ft.commit();
}
}
});
In the above case, I am opening LoginFragment when Button button is pressed, right now the user is in SignupFragment. So if addToBackStack(TAG) is called, where TAG = "SignupFragment", then when back button is pressed in LoginFragment, we come back to SignUpFragment.
Happy Coding!
By adding fragment_tran.addToBackStack(null) on last fragment, I am able to do come back on last fragment.
adding new fragment:
view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, new ChangePassword());
transaction.addToBackStack(null);
transaction.commit();
}
});
Following Kotlin code useful to me
1. Added in Simple Activity class with multiple fragments used
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
Log.i(TAG, "=============onBackPressed - Popping backstack====")
supportFragmentManager.popBackStack()
} else {
Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
super.onBackPressed()
}
}
2. Added in BottomNavigationView Activity class with multiple fragments used
override fun onBackPressed() {
Log.e(TAG, "=============onBackPressed")
val navController = findNavController(R.id.nav_host_fragment)
when (navController.currentDestination!!.id) {
R.id.navigation_comments, R.id.navigation_my_posts -> {
menuItemPosition = 0
navController.navigate(R.id.navigation_home)
Log.i(TAG, "=============onBackPressed - Popping backstack with First fragment ====")
}
else -> {
Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
super.onBackPressed()
}
}
}
I came here looking or the same idea, and in the meantime i came up with own, which I believe is not that bad and works if with ViewPager.
So what I did, is to override the onBackPressed method in the parent activity that holds the viewPager, and set it to always go back minus 1 position until it reaches the first fragment, then closes the activity.
#Override
public void onBackPressed() {
if(viewPager.getCurrentItem()>0){
viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
} else {
super.onBackPressed();
this.close();
}
}
private void close(){
this.finish();
}
This might have a downfalls, like it only goes back one way left each time, so it might not work great if there are tabs and you switch positions with fragments skipped, ( going from 0 to 2, and then pressing back would put you on 1, instead of 0)
For my case tho, with 2 fragments in viewPager without tabs, it does the job nicely.
getActivity().getSupportFragmentManager().popBackStackImmediate();
OR
getActivity().onBackPressed();
Try below code:
#Override
public void onBackPressed() {
Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if (myFragment != null && myFragment instanceof StepOneFragment) {
finish();
} else {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}

Categories

Resources