My project contains two fragment :
FragmentA : the fragment loaded by default when the app starts
FragmentB : replace the fragmentA when a click on a button is done.
This is the XML of my main view :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/main_fragment_container"
android:name="fragmentA"
android:layout_width="match_parent"
android:layout_height="match_parent">
</fragment>
</LinearLayout>
When I wish to replace the FragmentA by the FragmentB, I use this code :
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
.beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB());
fragmentTransaction.commit();
This code works fine. My FragmentA is replaced by the new FragmentB. But when a click is done on the back button, I wish replace the FragmentB by the FragmentA by using popBackStackImmediate().
This is the code I use:
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
boolean done = getFragmentManager().popBackStackImmediate();
fragmentTransaction.commit();
}
The function popBackStackImmediate return always false and the FragmentB still in foreground.
Why the FragmentA does not replace the FragmentB when I call popBackStackImmediate ? Is anybody has an idea to solve my problem?
thanks in advance
You use the getSupportedFragmentManager() to replace FragmentA by FragmentB. But you call popBackStack() on the getFragmentManager().
If you are adding the Fragments to the android.support.v4.app.FragmentManager you also have to call popBackStack() on the same FragmentManager.
This code should solve the problem:
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
boolean done = getSupportFragmentManager().popBackStackImmediate();
}
You should call
fragmentTransaction.addToBackStack(null);
after performing all operations such as add(), remove(), and replace() and Just before commit(). Only then this transaction will be added to backstack. Only then you will be able to return to previous fragment state with Back button. Details here.
The problem is you're mixing Fragment and methods from the support library.
If you are using the support library, make sure:
your Activity extends from the android.support.v4.app.FragmentActivity
your Fragment extends from android.support.v4.app.Fragment
use getSupportFragmentManager() to get the android.support.v4.app.FragmentManager
Your code in the Activity would be:
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
}
Please be aware that if you would like to get the FragmentManager from the Fragment code, you have to use the getFragmentManager method, as explained in the documentation (probably that's the cause of some confusion if you don't have much experience).
If you are not using the support library:
your Activity extends from the android.app.Activity
your Fragment extends from android.app.Fragment
use getFragmentManager() to get the android.app.FragmentManager
Your code would be:
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
}
fragmentTransaction.commit(); is not necessary in both cases, so remove it.
Also, please call fragmentTransaction.addToBackStack(null); just before the commit but after the other operations.
I will suggest using the fragment replacement with Tag to produce the same result .
Add the fragment B to activity with tag
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB(),"TAG_B");
Fragment A -> Fragment B [onBackPressed] -->Fragment A
Override the onBackPressed() in the Activity files where ,
// check for fragment B and you are viewing fragment B
if (getSupportFragmentManager().findFragmentByTag("TAG_B")!=null)
{
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentA(),"TAG_A");
}
addToBackStack("TAG") and popBackStackImmediate("TAG") always revert to fragment condition without any data in the UI right before fragment is created or added to activity !
The problem is in the order of your code. Here are two things you need to pay attention to.
You need to use addToBackStack() after your adding,
replacing fragment. Then commmit()
Then popBackStackImmediate can reverse the operation and it is working. I hope it solves the problem. I know it is an old post but I
do encounter a similar problem and wish this update can help others. Below should be the correct order:
FragmentTransaction fragmentTransaction =getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.main_fragment_container, new FragmentB());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
If you are Struggling with addToBackStack() and popBackStack() then simply use
FragmentTransaction ft =getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, new HomeFragment(), "Home");
ft.commit();`
In your Activity In OnBackPressed() find out fargment by tag and then do your stuff
Fragment home = getSupportFragmentManager().findFragmentByTag("Home");
if (home instanceof HomeFragment && home.isVisible()) {
// do you stuff
}
For more Information https://github.com/DattaHujare/NavigationDrawer I never use addToBackStack() for handling fragment.
Related
I've done some research but I really couldn't find the answer.
I have single activity with side menu, and holder. I have many (non support) fragments, and all of them are using same holder (one at a time).
When user uses menu (it's in main activity), and goes another page, I want to add name of the current fragment to backstack (using .addToBackStack(Fragment1.class.getName())), but I couldn't find how to get current fragment.
I don't want to implement interface etc to keep track of current fragment. There is a super simple way using fragmentManger isn't there?
You can get your current fragment like this:
if (getFragmentManager().getBackStackEntryCount() > 1) {
Fragment f = getFragmentManager().findFragmentById(R.id.content_frame);
if (f instanceof BlankFragment) {
// Do something
}
}
OK,
If you want to get latest entry from backstack(thanks to #AndroidGeek);
fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1);
and, if you want to get currently active fragment (thanks to #Salman500 #AndroidGeek);
Fragment f = getFragmentManager().findFragmentById(R.id.fragment_holder);
you can use this to get fragment id for non support fragment
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_id);
if(fragment!=null)
{
getFragmentManager()
.beginTransaction()
.addToBackStack(null)
.commit();
}
You can keep track of fragments in the main activity (with variables) and access them there. Example:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
MyFragment myFragment = new MyFragment();
myFragment.doSomething();
Adding to the back-stack:
FragmentTransaction fragment = getSupportFragmentManager().beginTransaction();
fragment.addToBackStack(fragment);
fragment.commit();
This is answered here: get currently displayed fragment
Just use addToBackStack() before you commit() the fragment trancsaction. See it here
So your code will look like :
...
fragmentTransaction.replace(R.id.holder, newFragmentToShow, newFragmentTag);
fragmentTransaction.addToBackStack();
fragmentTransaction.commit();
...
EDIT : after OP was edited
You do not need the fragment class to call addToBackStack() as you have mentioned in the OP. The String argument is an optional string just to keep the state for the backstack state. You should see the documentation
It is all internally managed and the current active fragment is automatically added to the backStack, you may call it from where ever you want, it will always use current active fragment.
I have a problem with the backstack behaviour. That is what I am doing:
add(fragment1) + addToBackStack(null)
replace(fragment2) + addToBackStack(null)
What is happening:
Fragment 1 is added and in the backstack
Then the second fragment replaces the first one and it is added to the backstack.
Now I want to change my last backstacked fragment with a new transaction which put a new backstack fragment so:
[frag1, frag2] becomes [frag1, frag3]
but this transaction made by a popBackStack + replace is making the frag1 to load by calling its onCreateView and onActivityCreated. I know this is the expected behaviour since this is how backstack works, but I am trying to find a way to avoid this preload.
Edit
In this question I am using the concept of backstack fragment for the transaction to be more clear. Every transaction here is an add+remove (which is a replace).
The code for replace I am using is:
public int replaceFragment(BaseFragment newFragment, boolean addToBackStack, boolean animated, PopStackMode popMode) {
if (popMode != null) {
getSupportFragmentManager().popBackStack(newFragment.getFragmentTag(), popMode == PopStackMode.POP_INCLUSIVE ? FragmentManager
.POP_BACK_STACK_INCLUSIVE : 0);
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (animated) {
ft.setCustomAnimations(R.anim.slide_in_left, 0, R.anim.slide_out_right, 0);
}
ft.replace(R.id.fragment_container, newFragment, newFragment.getFragmentTag());
if (addToBackStack) {
ft.addToBackStack(newFragment.getFragmentTag());
}
return ft.commit();
}
You can see I am creating a navigation history based on the fragment backstack, as it was kind of a browser. When a "page" is added there is a fragment and a backstack transaction. In this context, I trying to:
Remove the current fragment.
Remove the transaction from the backstack.
Add a new fragment without poping and loading the previous backstack fragment.
I hope it is more clear.
Edit 2
I have filled a request feature for a flag that supports this behavior. Find it here.
First, you should understand that the backstack doesn't save fragments, but it saves transactions instead. When you call popBackStack what it actually does is revert the previous transaction. More on this here.
I think that you can do this:
Name your transactions by providing a unique name to your addToBackStack instead of null. i.e. addToBackStack("frag1").
Don't call popBackStack + replace, but instead just call replace.
Then, in your activity, override your onBackPressed and if the current fragment being displayed is Frag3 (you can check this using findFragmentByTag if you provided a tag in the replace method) you can call getSupportFragmentManager().popBackStackImmediate("frag1", FragmentManager.POP_BACK_STACK_INCLUSIVE); (otherwise call the super.onBackPressed)
I am develop the app using the fragments and i am facing one fragment1 adding to the another fragment2
fragment1 onclicks performing fragment2 .I didn't findout the solution for that. please guide anyone know
I am using the following code to add the fragment
Fragment2 fragment2=new Fragment2();
FragmentManager fragmentManager = activity.getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.container,fragment2);
ft.hide(new Fragment1());
ft.addToBackStack(Fragment1.class.getName());
ft.commit();
The above to use adding onefragment1 adding to fragment2.Fragment1 onclicks perform to fragment2 . i didn't findout mistake.
please guide me anyone know .Advance thanks to all
nested Fragments are not recommended and for adding a fragment to a container from another Fragment use the parent Activity to do so , you can define a function inside Parent Activity which replace current Fragment with your second Fragment and call it from your first.
Adding a fragment to another fragment is the concept of nested fragments and not recommended. You should replace the fragment instead of adding. Use the following:
Fragment fragment = new Fragment2();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().addToBackStack("fragment").replace(R.id.frame_container, fragment).commit();
I've been working with fragments for a while now, but I regularly encounter a problem that just annoys me. Fragments remain drawn over each other some times. Now, I managed to isolate one use case for this, and it goes like this:
Add Fragment A (also use addToBackStack with a name "backstack_state")
Replace Fragment A with Fragment B (use addToBackStack)
Replace Fragment B with Fragment C WITHOUT using addToBackStack
at a given point use popBackStack("backstack_state", 0) and here comes the issue:
The backstack is popped until Fragment A but Fragment C is overlaid with Fragment A, both are visible at the same time. Is this normal behavior or is it me who makes a mistake?
Here's a remark also: all the fragments have transparent background.
Thanks!
This happens because the top fragment (in this case Fragment C) is not removed. You have to remove it first inside a fragment transaction. Try this:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment topFragment = fragmentManager.findFragmentById(R.id.fragment_container);
if (topFragment != null) {
fragmentTransaction.remove(topFragment);
}
fragmentTransaction.commit();
fragmentManager.popBackStack("backstack_state", 0);
I have class Demo and I am extends the demo by FragmentActivity class. Also I have another class Fragment1 extends Fragment. And the onclick of button i am navigate from activity Demo to the Fragment Fragment1. Now I want to come back on Demo from the Fragment1. So how can I back to Demo activity?
Thanks.
Your question is lacking a lot of detail, so I'm taking a stab in the dark here, but...
I presume in your onClick code, you use the Fragment Manager to create a new Fragment Transaction, then add the fragment to that transaction and commit it?
Your problem with the activity being closed when you hit the back button is likely because your fragment was not added to something called the "back stack". You can find to documentation here http://developer.android.com/reference/android/app/FragmentTransaction.html#addToBackStack%28java.lang.String%29, but crucially the main thing you need to do is modify your code to include the line below:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, new Fragment1());
fragmentTransaction.addToBackStack("Transaction ID"); // <-- This is key!
fragmentTransaction.commit();
Once that's done, Android will remember the adding of the fragment as a navigation act, and should reverse the transaction when the back button is hit.
If this wasn't what you're looking for, or if it doesn't work, please provide some more detail and some code samples and I can take another look.
Try adding the fragment you want to go back to manually to the backstack.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
YourFragmentName myFragment = new YourFragmentName();
transaction.replace(R.id.fragment_container, myFragment);
//if you with to add it to backStack, do this, otherwise skip the line below
transaction.addToBackStack(null);
transaction.commit();