fragment backstack replace issue - android

I have fragments in backstack which is added by using addtobackstack function.
When i add a fragment without not using addtobackstack function and then press back button, the backstack is go back to wrong fragment.
For example:
Fragment A is replaced by using addtobackstack
Fragment B is replaced by using addtobackstack
Fragment C is replaced without not using addtobackstack
Fragment D is replaced by using addtobackstack
When i was in Fragment D and press the back button, i am going to Fragment A. But i must go to Fragment B.
How can i fix it?
Thanks,

Put this code in Activity then try.
Fragment is followed with Activity so when you use fragment with addToBackStack() with tag or passing null will add fragment in stack with help of FragmentManager.
Not necessary to addToBackStack(). comment this code or pass null
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager .beginTransaction();
fragmentTransaction .replace(R.id.fragment_container, YouNextFragment);
fragmentTransaction .addToBackStack(null);
fragmentTransaction .commit();
When you press back button in Activity FragmentManager automatically popUp latest added fragment.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (getFragmentManager().getBackStackEntryCount() ==0) {
finish();
}else{
getFragmentManager().popBackStack();
}
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}

Related

Handle Back Button Key during Fragments

Actually the Problem is i just load a Fragment(let call be Fragment-A) From the Navigation Drawer now the Fragment-A call a Dummy Activity, and the Dummy Activity Load a Fragment-B than fragment-B call a Fragment C and the fragment-C call the Fragment-D..
Overall Above picture:
Fragment-A(call)-->Dummy Activity(load)-->fragment-B(call)-->fragment-C(call)-->fragment-D(call)
Now i have Some Question Regarding this:
Actually there is one button in Fragment D, when the button is invoke i have to go back to the Fragment-A
now During the fragment(B,C& D) load i have to handle the On Back Pressed..
means if user in fragment D than on back press, than Fragment-C is load and vice versa but when the user is on Fragemnt-B an invoke the On-back key than Fragment A is load
NOTE :
i have to handle Both Above Back key or System Back Key
I know i have to maintain the Fragment Stack but how can i pass the case one
Edit:
Actually the Fragment-A is the Part of Activity-(a) and the remaing Fragmnets(B,C&D) is the Part of Activity-(X)
Code:
Repo link : Code link
The above scenario can be solved by below..
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
finish();
}
If the button in the fragment D invoked, please call the function
getActivity().onBackPresses();
It will finish the current Activity..
You need to add the fragments in backstack as follows:-
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentA);
//No need to put fragment A in backstack
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentB);
ft.addToBackStack(null);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentC);
ft.addToBackStack(null);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragmentD);
ft.addToBackStack(null);
ft.commit();
Now, All your fragments are in backstack so if you press Back on fragmentD then fragmentC will be shown and on pressing Back in fragmentC, fragmentB will be shown and on pressing Back in fragmentB, fragmentA will be shown.
AS, you mentioned you have a special button in fragmentD which on pressing should take you on fragment A, So on clicking that button execute this code:-
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}

Maintain fragments-backstack of previous Activity

I have 2 Activites A & B, In Activity A I managed fragment back stack but in one case as like below:
I have 4 fragments in Activity going from fragment 1 to 2 to 3 to 4 then from 4th fragment I'm going to Activity B now what i want is on press of back button fragment 4 of Activity should be opened and then on back fragment 3 and so on.
I'm using following function to replace the fragment and manage back stack
private void changeFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction().replace(R.id.act_home_fl_container, fragment).commit();
}
On back press
boolean isPopFragment = getSupportFragmentManager().getBackStackEntryCount() > 0 ? true : false;
if (isPopFragment) {
getSupportFragmentManager().popBackStack();
}
I got success upto here but when I'm going to Activity B from 4th fragment and coming back to Activity A, I'm not able to manage back stack of fragments of Activity A.
I'm not having any how to start with it.
you can override onBackPressed inside your activities, check which fragment is on top and decide what to do as you wish:
#Override
public void onBackPressed()
{
// code here
super.onBackPressed(); // check if you need this, depends on your needs
}
Use this code to change fragment
public static void addFragment( final Fragment newFragment, final Fragment hideFragment) {
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.hide(hideFragment);
fragmentTransaction.add(R.id.activity_home_container, newFragment, newFragment.getClass().getSimpleName());
fragmentTransaction.addToBackStack(hideFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss();
}
newFragment "Fragment you want to add"
hideFragment "Fragment which is on container"
just use addToBackStack(tag_name) before commit
You can add en extension function in kotlin
fun AppCompatActivity.replaceFragment(containerId: Int, fragment: Fragment) =
supportFragmentManager.beginTransaction()
.replace(containerId, fragment, fragment.javaClass.name)
.addToBackStack(fragment.javaClass.name).commit()

How to replace more than one fragments with another one in the back stack?

I have the following fragments in the back stack A, B, C. Then I want to add fragment D, but in the back stack I want to put A and D instead of A, B, C, D.
The problem is when I try to remove B and C with transaction.remove(), the backStackEntryCount is still the old one, which makes empty screens while pressing back. Is there a way to handle this?
When I use popBackStack()it goes to fragment A then comes D, which makes weird animation effects.
EDIT:
The question is not duplicate as it was marked, because this question is more about to control the order of several fragments in the back stack.
When adding to the Backstack, you can include a name to pop the backstack to when you're in a specific state. Based on the documentation for FragmentManager#popBackStack(string, int);:
Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned. 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.
Parameters
name String: If non-null, this is the name of a previous back state to look for; if found, all states up to that state will be popped. The POP_BACK_STACK_INCLUSIVE flag can be used to control whether the named state itself is popped. If null, only the top state is popped.
flags int: Either 0 or POP_BACK_STACK_INCLUSIVE.
So in this case you:
Add fragment A to the container and to the root backstack. Give it a name so you can reference it when popping.
Fragment A:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentA, "FragmentA")
.addToBackStack("first")
.commit();
Add Fragment B to the container (replace or add, doesn't matter). Add to the backstack with a "null" or another name if you prefer. It must be different than "first".
Fragment B:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentB, "FragmentB")
.addToBackStack(null)
.commit();
Add or replace with Fragment C like you would with Fragment B.
Fragment C:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentC, "FragmentC")
.addToBackStack(null)
.commit();
Add or replace with Fragment D like you would with Fragment B and C.
Fragment D:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentD, "FragmentD")
.addToBackStack(null)
.commit();
Then, in onBackPressed() you first check if "FragmentD" is in the stack. If it is, then pop all the way back to the root (which in this case is "first"). If not, just handle the back pressed like you normally would.
#Override
public void onBackPressed() {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag("FragmentD") != null) {
fm.popBackStack("first", 0); // Pops everything up to "first"
} else {
super.onBackPressed(); // Pops backstack like normal or leaves App if at base.
}
}
What this should do is allow your users to go "back" when they press the back button in Fragments A, B, or C. Then when they're finally in Fragment D, it will pop all the way back to A.
Fragment A
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, FragmentA, "FragmentA");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Fragment B
fragmentTransaction.replace(R.id.fragment_container, FragmentB, "FragmentB");
Fragment C
fragmentTransaction.replace(R.id.fragment_container, FragmentC, "FragmentC");
Fragment D
fragmentTransaction.replace(R.id.fragment_container, FragmentD, "FragmentD");
Now your onBackPressed() in activity
#Override
public void onBackPressed() {
int lastStack = getSupportFragmentManager().getBackStackEntryCount();
try {
//If the last fragment was named/tagged "three"
if (getSupportFragmentManager().getFragments().get(lastStack).getTag().toString()=="FragmentD"){
getSupportFragmentManager().popBackStackImmediate();//skip c
getSupportFragmentManager().popBackStackImmediate();//skip B
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentA");
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
return;
}
} catch (Exception e) {
e.printStackTrace();
}
super.onBackPressed();
}
make fragment_container for each of the fragment and keep on replacing the newest fragment's fragment_container..
Dont forget:
addToBackStack(null);

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();

Android FragmentManager calls onCreateView while clearing fragments

I have these methods for fragment manipulation:
public void replaceFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_frame, fragment);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
}
public void addFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.main_frame, fragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(fragment.getClass().getName());
}
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
}
public void clearFragments() {
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry first = fragmentManager.getBackStackEntryAt(0);
fragmentManager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Scenario:
I start with fragment A, when activity is created. addFragment(new A, false);
Then I add fragment B. replaceFragment(new B);
I add another fragment C. addFragment(new C);
In C fragment I want to reset application to A fragment. I call clearFragments(); addFragment(new A, false);
The problem is that B fragment onCreateView is called after pressing button on C fragment that clears fragments and adds A fragment. I don't see the fragment, but it starts background thread that crashes my app. I need to clear all fragments without calling their onCreateView() methods.
Is this expected behaviour, or am I doing something wrong?
Actually in such a scenario you will always return to the fragment B.
Step by step:
Adding A.
Replacing A with B <- after this step you don't have A within your activity.
Adding C. Here you are adding another fragment and telling FragmentManager to preserve current state of fragments to the back stack. Your current state at this point is fragment B. Then fragment C is added.
When you call clearFragments, FragmentManager returns to the first saved state - and this state is fragment B.
Maybe you forgot to mention something? I tried to put several entries in a back stack and then reset to the first state - onCreateView is called once, only for the first fragment.

Categories

Resources