Hello I am working with sliding menu with fragment.
Indivisual fragment works properly. But suppose user navigates From fragment A->B , now 'B' works perfect and now if user goes from B->A than fragment 'A' is called from onAttach() .
I want such a condition if any fragment is opened , than reopening it should not load whole fragment , it should be resumed just like we handle activity with Intent.FLAG_ACTIVITY_REORDER_TO_FRONT.
Here is my code...
FragmentManager fm = MainActivity.this.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Layout1 fragment = new Layout1();
ft.add(R.id.activity_main_content_fragment, fragment,Layout1.class.getName());
ft.addToBackStack(Layout1.class.getName());
ft.commit();
Answer updated:
Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.
Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.
So if you want to store state you should use instance variables and not rely on onSaveInstanceState()
Check this link. it will help How to resume Fragment from BackStack if exists
Related
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 have two fragments - Listing and detail. Initially I load the listing fragment in the container of the activity using
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, listingFrag);
ft.commit();
On tapping an item in the listing fragment I load the detail fragment using
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, detailFrag);
ft.addToBackStack(null);
ft.commit();
On loading detail fragment I do not get the onPause call of the listing fragment. Neither do I get the onResume call of the listing fragment on coming back from detail fragment (using the system back button).
Also, when I am in the detail fragment, putting the app to background calls the onPause of both the listing and detail fragments. On getting back the app from background, onResume of both listing and detail screens get called.
The above mentioned behaviors are quite unexpected.
I would want
1) listing fragment's onResume to be called on coming back from listing screen
2) listing fragment's onPause to be called on loading detail fragment
3) only detail fragment's onPause to be called when the app is put to background
4) only detail fragment's onResume to be called when the app is brought back from background
Can some one please explain a way to do this.
Thanks in advance!
onPause and onResume in fragment are just the reflection of onPause and onResume in Activity.
So every time you go from one activity to another all the fragments of the first activity will call onPause and all the fragments of the 2nd activity will call onResume.
This functions are not for fragment visible/add or remove.
When you display the detailed fragment, you add it which means that both the listing and the detailed fragments are active at the same time. Hence both of them receive onPause() and onResume().
You should instead try replacing the listing fragment with the details fragment. That will cause onPause() in the listing fragment and only one fragment will be active at a time.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, listingFrag);
ft.addToBackStack(null);
ft.commit();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, detailFrag);
ft.addToBackStack(null);
ft.commit();
I have android screen layout shown below
Apps screen divided into 3 fragments, Header, Footer and Content. Header and Footer fragments are fixed. Content fragment is changing according to content. I replaces fragment1-fragment3 according to need. Initially Fragment1 is shows in content area. When i press a next button fragment1 is replace by fragment2. This is the order. I have question, if i press another button previous, how can i return to previous fragment ( fragment2 -> fragment1). Is any built in mechanism available in fragment class.
Please guide me...
thanks in advance
try this code
FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();
Whenever you try to call new fragment then add back stack for it through
ft.addToBackStack(null);
And now if you want to back from one fragment to another then, make one method..
public void DeleteCurrentFragment()
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager().findFragmentById(R.id.detailFragment);
String fragName = "NONE";
if (currentFrag!=null)
fragName = currentFrag.getClass().getSimpleName();
if (currentFrag != null)
transaction.remove(currentFrag);
transaction.commit();
}
And after that call this:
getSupportFragmentManager().popBackStack();
DeleteCurrentFragment();
you can try something like:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.add(R.id.contentFragment, <your fragment>);
ft.addToBackStack(null);
ft.commit();
so suppose you're on fragment1 and after doing some stuff you want push fragment2 then on your contentFragment you can add or replace the fragment (fragment2 in this case) as per your requirement. Now when you call addToBackStack it means add this transaction to the back stack. So that the transaction will be remembered after it is committed, and will reverse its operation when later popped off the stack. Internally it maintains a stack so you don't want to do anything. At last when you press back button from fragment2 it checks whether the transaction having any fragment in its stack, if yes then it calls it. Its like top of stack. When you call addToBackStack in that stack fragment1 is added. So when you press back button stack's top is fragment1 so it calls it.
It happens when you press hardware back button. If you want to do this on any button, then on that button's click listener simply onBackPressed() method.
I have following issue with Android compatibility package fragments.
There is following hierarchy of fragments:
A(login) -> B(dashboard) -> C(details)
Login fragment is added with function:
private void addFragment(Fragment f) {
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.replace(R.id.main_content, f);
ft.commit();
}
After successfull login dashboard is added same way, without adding transaction to backstack. C fragment is added like:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.main_content, f, id);
ft.addToBackStack(null);
ft.commit();
So basically on detail screen I have logout button, which should bring me to login A and remove all fragments from backstack. According to android developer docs:
Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.
But it is not the issue in my case. When logout is pressed in C fragment:
getFragmentManager.popBackStackImmediate();
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.replace(R.id.main_content, new LoginFragment());
ft.commit();
onActivityCreated(), onStart() of B fragment are also called (instead of onResume written in docs), making my code crash because in this fragment Im starting some thread operation, and after adding login fragment I got IllegalStateException that fragment B is not attached to an activity (when thread operation is over it updates fragment UI) Do anyone knows how replace really works and how overcome this problem?
I guess you should call
addToBackStack for each fragment you add giving a different name to them.
Reading your code seems to me you don't do it.
Is there any way to clean up fragments' state?
I mean such situation:
I create a fragment instance (lets call it A) passing it an ID to load some content, than return to previous fragment (B for example). And when I go to A again, passing NO ID (it should than load default data) - it already has an ID from previous usage and my logic breakes.
Do not add your 'A' to backstack. So it will not be saved into backstack. Whenever you go back and come again it will not be added. Is this what you want right.
// Instantiate a new fragment.
Fragment newFragment = CountingFragment.newInstance(mStackLevel);
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
//ft.addToBackStack(null);// Do not add to backstack here.(add every time new).
ft.commit();