Backstack Fragment not appearing in front on Back button prerssed - android

I have gone through many stackoverflow question before writing this. i am so confused about this guy Backstack in fragment.
I have Added three fragment on the same container inside an Activity
Fragment 1 :
private void addLandingFragment() {
landingPageFragment = LandingPageFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Fragment 2 :
public void addIntrofragment() {
fragment2 = IntroFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
transaction.addToBackStack(fragment2.getClass().getName() );
transaction.commit();
}
Fragment 3 :
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Now what I want is when user presses back button on fragment 3 it should come on very first fragment so I have overrided the onBackPressed() method.
#Override
public void onBackPressed() {
manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );
}
but nothing happening on screen it keeps fragment 3 running.
UPDATE
When I am navigating from
fragment1 > fragment2
and presses back button on fragment2, I am coming to fragment1 but if move from
fragment1 > fragment2> fragment3
I am getting the stack entry count 1 on onBackPressed() method but on device screen it still shows fragment3. Now pressing back button again will exit me from app but fragment1 wont come on screen. So puzzling why it is happening ?
Any solution to achieve this.

calling replace() will remove the previous fragment, Fragment 1 should be called using replace(), and Fragment 2 & 3 should be called using add(), you should also add the last transaction to back stack (calling Fragment 3)
Like this:
Fragment 1:
private void addLandingFragment() {
landingPageFragment = LandingPageFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
transaction.commit();
}
Fragment 2:
public void addIntrofragment() {
fragment2 = IntroFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction .hide(LandingPageFragment.this);
transaction.add( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
transaction.addToBackStack(fragment2.getClass().getName() );
transaction.commit();
}
Fragment 3:
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
fragmentManager.popBackStackImmediate(); // to remove fragment 2
transaction.add( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.addToBackStack(fragment3.getClass().getName() );
transaction.commit();
}
finally your onBackPressed should be like this:
#Override
public void onBackPressed() {
fragmentManager.popBackStackImmediate();
fragmentTransaction.show(LandingPageFragment.this);
}
therefore your onBackPressed will always pop the top fragment on the stack (Fragment 3), and since Fragment 2 was already popped before adding Fragment 3, then onBackPressed will display the very first fragment.

Thanks Silvia.H for you support. I have solved my problem and found it as the best possible solution for me.
The only mistake I did was, I did not add fragment3 in backstack
So the only changes required was
public void onGetStartedClicked() {
fragment3= ConnectFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
transaction.addToBackStack(ConnectFragment.class.getName() );
transaction.commit();
}
Now this makes you clear that in order to use popBackStack with name like
manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );
you have to keep that transaction in backstack from where you are actually pressing the back button.
I have made one more small change in onBackPressed() method which allows the app to exist when user presses back button on fragment1.
My onBackPressed() look like this now
#Override
public void onBackPressed() {
if( manager.getBackStackEntryCount() > 0 ) {
getSupportFragmentManager().popBackStack(
scoreTrackerIntroFragment.getClass().getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE );
}else {
super.onBackPressed();
}
}
Woop! Now I am clear about this "Backstack" guy.

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.

popBackStackImmediate not showing fragment when the current fragment transaction is not added in the backstack

Popbackstack is working fine when all the fragments in the sequence are added in the backstack but isnt working when one of the transactions is not added in the backstack.
Here is my navigation:
1.Replace fragment to load home fragment. This transaction not added to backstack.
Replace fragment to load login fragment. This transaction is added to backstack.
3.Replace fragment to load loggedin fragment. This transaction is not added to backstack.
Now, when i press back button once nothing happens. Whereas ideally it should go to the home fragment from logged in fragment.
Here is my onbackpressed method in main activity:
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()>0)
{
FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1);
String str = backStackEntry.getName();
FragmentManager fm=getSupportFragmentManager();
//getSupportFragmentManager().popBackStackImmediate();
fm.popBackStack(str, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
else {
super.onBackPressed();
}
}
popBackstack only 'pop' what is in the backstack.
Since you haven't add the transaction when replacing the LoginFragment by the LoggedInFragment when you press back:
the LoggedInFragment remains,
the LogInFragment is popped
the HomeFragment is displayed
But because the LoggedInFragment as been added after the HomeFragment, the HomeFragment is displayed underneath it. So you can't see it as hidden by the LoggedInFragment.
One solution is to add the transaction to the back stack when you replace the LogInFragment by the LoggedInFragment.
Then in onBackPressed you test if the current fragment is the LoggedInFragment. If it's the case you pop the back stack up to HomeFragment (not inclusive). Like that both LoggedInFragment and LogInFragment will be pop.
EDIT
#Override
public void onBackPressed() {
FragmentManager manager = getSupportFragmentManager();
Fragment fragment = manager.findFragmentById(R.id.my_fragment_container);
// If there is something in the back stack AND the current fragment is the LoggedInFragment
if (manager.getBackStackEntryCount() > 0
&& fragment instanceof LoggedInFragment) {
manager.popBackStack(HomeFragment.class.getSimpleName(), 0);
} else {
super.onBackPressed();
}
}
In order to retrieve the HomeFragment by name you need to tag your transaction when you replace the current fragment by the HomeFragment. Generally I tag all transactions with the fragment's class simple name so like that I can retried any fragment:
transaction.replace(R.id.my_fragment_container, fragment, fragment.getClass().getSimpleName());
Eselfar's explanation of the problem is correct, but the code he provided wasn't generic enough for me.
I (hopefully) resolved this issue in a general case by the following code:
#Override
public void onBackPressed() {
Fragment currentFragment = getCurrentFragment();
if (mFragmentManager.getBackStackEntryCount() > 0) {
// In a normal world, just popping back stack would be sufficient, but since android
// is not normal, a call to popBackStack can leave the popped fragment on screen.
// Therefore, we start with manual removal of the current fragment.
removeCurrentFragment();
mFragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private Fragment getCurrentFragment() {
return mFragmentManager.findFragmentById(getContentFrameId());
}
private void removeCurrentFragment() {
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.remove(getCurrentFragment());
ft.commit();
// not sure it is needed; will keep it as a reminder to myself if there will be problems
// mFragmentManager.executePendingTransactions();
}

Android fragment handling back button

I am creating an application with multiple fragments. I have four fragments fragment1, fragment2, fragment3, fragment4. I am moving from different orders like f1 -> f2 -> f4 -> f3 -> f1 or any other order. But when I click the back button from each fragment I need to go to the previous fragment. How to handle this.
Edit 1:
I already tried
FragmentManager fm = ((Activity) context).getFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
fm.popBackStack();
}
Which is not help me to solve my issue.
Sample code of Manage Fragment back stack
private Stack<Fragment> stack = new Stack<Fragment>();
public void pushFragments(Fragment fragment, boolean shouldAnimate,
boolean shouldAdd) {
drawerClose = false;
if (shouldAdd)
stack.push(fragment);
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, shouldAnimate, false);
}
public void popFragments() {
/*
* Select the second last fragment in current tab's stack.. which will
* be shown after the fragment transaction given below
*/
Fragment fragment = stack.elementAt(stack.size() - 2);
// / pop current fragment from stack.. /
stack.pop();
/*
* We have the target fragment in hand.. Just show it.. Show a standard
* navigation animation
*/
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, false, true);
}
private void changeFragment(Fragment fragment, boolean shouldAnimate, boolean popAnimate) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAnimate)
ft.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left);
if (popAnimate)
ft.setCustomAnimations(R.anim.slide_in_left,
R.anim.slide_out_right);
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
//On BackPress just check this thing
private void backManage() {
if (stack.size() > 1) {
popFragments();
}
}
Use addToBackStack(String tag), while committing the fragment to add the fragment into the stack of your application:
getFragmentManager().beginTransaction().replace(fragmentContainer.getID(), fragment)
.addToBackStack(null).commit();`
on Activity
#Override
public void onBackPressed() {
if(check_if_backstack_is_null)
super.onBackPressed();
else
{
popupFromBackstack();
}
}
You should override onBackPressed method:
#Override
public void onBackPressed() {
if (fragment != null && fragment.getChildFragmentManager().getBackStackEntryCount() > 0){
fragment.getChildFragmentManager().popBackStack();
}else {
super.onBackPressed();
}
}
For this you can set addToBackStack to fragment transation and then call commit.
By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Back button.
If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the Back button will reverse them all together.
You just need to add addToBackStack(null) by FragmentTransaction.
when you are calling next Fragment just add this method with null parameter.
Like this.
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(..............);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Use this lines of code for it:-
#Override
public void onBackPressed() {
if ( getSupportFragmentManager().getBackStackEntryCount() > 0){
fm.popBackStack();
}else {
super.onBackPressed();
}
}
To get the backStack functionality in your fragmentthan you should have use the .addToBackStack(null) , while performing the fragment transaction like below:-
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.YOUR_CONTAINER, YOUR_FRAGMENT,"TAG")
.addToBackStack(null) /// IT IS NECESSARY TO GET THE BACK STACK PROPERTY IN YOUR FRAGMENT
.commitAllowingStateLoss();

Android: Check if fragment exits in Stack and reuse it

Hi I am using a Stack variable for storing the sequence of fragments clicked by the user
For example : [A,B,C,A,D]
Now I need to check if a fragment exits in the stack I need to reuse it.
From the above example I need to reuse the first element i.e, A when user clicks on the fourth time.
The problem is I have a custom keyboard opening in fragment A, now if the same fragment is in the stack as forth element the keyboard is not opening .but when I backpress and go to first element keyboard is opened in the first instance of A
Code for storing in the Stack
public void switchContent(Fragment fragment) {
if(mContent !=null && (fragment.getClass().toString().equals(mContent.getClass().toString()))){
getSlidingMenu().showContent();
return;
}
mContent = fragment;
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.content_frame, mContent);
FragmentChangeActivity.fragmentStack.lastElement().onPause();
FragmentChangeActivity.fragmentStack.push(mContent);
ft.commit();
getSlidingMenu().showContent();
}
Code for backpress
#Override
public void onBackPressed() {
if (fragmentStack.size() >= 2) {
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentStack.lastElement().onPause();
ft.remove(fragmentStack.pop());
fragmentStack.lastElement().onResume();
ft.show(fragmentStack.lastElement());
ft.commit();
} else {
super.onBackPressed();
}
}
Any help is appreciated.
The following code check's if Fragment named SearchFragment exists or not in backstack and processes accordingly. You can use this logic to determine if a specific Fragment exists or not
FragmentManager fragmentManager=getSupportFragmentManager();
Fragment currentFragment = (Fragment)fragmentManager.findFragmentById(R.id.mainContent);
if(currentFragment!=null && currentFragment instanceof SearchFragment){
//SearchFragment exists in backstack , process accordingly
}else{
//SearchFragment not present in backstack
}

Fragment back stack, android?

My activity consists of navigation drawer and currently have 5 options in the left menu. Which all opens in fragment.
I am looking for a way to keep a stack of all the fragments so when the user presses back button he moves to previous fragment.
Like- Activity consists of drawer menu which have 5 options menu1, menu2, menu3, menu4, menu5 having corresponding fragments F1, F2, F3, F4, F5.
User presses menu1 he is forwarded to F1
Then presses menu2, and then menu4.
When the user is at F4 and he presses back he should be moved to F2 rather than exiting the activity or app.
How can it implemented and example or sample code preferred.
I currently use this code but it does not help me out
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
I found some workaround for your query :
Override onBackPressed() in code
Use methods related to backstack maintained which contains your all fragment transactions
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack(); // this will display last visible fragment
getActinBar().setTitle(mTitle); // save your title in some variable and restore here
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed(); // system will handle back key itself
}
}
Reference answer : this
I used to replace Fragment like as below :
public void replaceFragment(Fragment fragment, boolean addToBackStack, int transition) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.activity_main_relative_container, fragment, fragment.getClass().getName());
ft.setTransition(transition);
if (addToBackStack) {
ft.addToBackStack(fragment.getClass().getName());
}
ft.commitAllowingStateLoss();
}
// While to replace Fragment
replaceFragment(mFragment, true, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// False for not adding Fragment in back stack and true to add.
Hope this helps.
You need to add fragment to backstack
private FragmentTransaction m_fragmentTransaction;
FragmentOne m_fragOne = new FragmentOne();
m_fragmentTransaction = m_fragmentManager.beginTransaction();
m_fragmentTransaction.replace(R.id.dl_flContainer, m_fragOne , FragmentOne.class.getSimpleName());
m_fragmentTransaction.addToBackStack(FragmentOne.class.getSimpleName());
m_fragmentTransaction.commit();

Categories

Resources