I'm trying to understand some odd behavior. I have an ActivityA that calls a method in onCreate() to add FragmentA to R.id.fragment_container. Inside FragmentA I have a button that attaches FragmentB by using ActivityA's fragment manager (getActivity().getSupportFragmentManager()) and replacing the R.id.fragment_container and I also add it to the backstack. I also have another button that starts a new ActivityB.
When I navigate back from ActivityB I get: ActivityA onResume(), FragmentA onResume(). But when I navigate back from FragmentB I get: FragmentB onCreateView(), FragmentB onActivityCreated() then the 2 onResume().
So my questions is...why is the view state saved when a new activity is launched and not when the fragment is replaced and reattached. It looks much better to just restore that state rather than recreate the views and fetch that data again. This seems like opposite behavior from what I would expect so I'm clearly missing some fragment state saving/restoration step or something. It seems like the activity is just pausing FragmentA (and ActivityA) when ActivityB is launched and restoring it on back pressed but when FragmentB is attached FragmentA gets completely destroyed. I'm sure there's a way to prevent this I just can't seem to figure it out. Thoughts?
Just below your question are four tags android,android-fragments,android-lifecycle& android-navigation .Put your cursor over it for a while a black box will pop up . click on info tab and you will get best links to study that topics along with links to books .
Hope this will help you
Related
So right now I have a situation in which I have three fragments are committed in such an order:
Fragment A -> Fragment B -> Fragment C
Then, I start an Activity from Fragment C. The issue arises when I want to pop the back stack so the user is brought to Fragment B after the activity finishes. If I attempt to pop the back stack from the Activity before calling finish(), I get an IllegalStateException, saying that the action cannot be performed after onSaveInstanceState. Thus, is it even possible to make changes to the FragmentManager responsible for the fragments from the Activity?
How does this sound myrocks2? Android: how to make an activity return results to the activity which calls it?
First activity can start a second activity and expect a result. Upon getting back a result it knows second activity did its job, and now it's required to remove fragment c. (I don't know the logic of your app, but that can work)
Someone who thinks he is so smart gave you a negative vote, but I made sure to go away. There are no dumb questions.
I have FragmentX in a ViewPager. FragmentX has EditText's in it and a Button. The user presses the Button and FragmentY replaces FragmentX. The user then presses back and FragmentX has lost all of its input from the user.
How do you either:
a) Save the data in FragmentX before FragmentY appears then FragmentY is replaced by FragmentX retrieve the data and fill in the EditText's in FragmentX
(please don't reply with OnSaveInstanceState, as this does not work unless the Fragment is destroyed, which in this case it is not)
b) somehow keep the data in FragmentX so it is there when we go back to FragmentX from FragmentY..
Any suggestions?
Using addToBackStack() might help in your case.
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 out: Maintaining fragment states
I am now saving the data in FragmentX to SharedPreferences and overriding onBackPressed in the Activity, and have created a function in the Activity called popFromBackstack where the popBackStack() occurs.
In the functions in my Activity where i replace my Fragments i am now saving the data in FragmentX into SharedPrefs before the replace. I am also checking after the replace if the new Fragment is FragmentX and, if it is, i am filling the data into FragmentX from SharedPrefs.
I am also saving the data from FragmentX in onBackPressed in my Activity (if the current fragment is FragmentX), incase the user presses the back button.
I have also created a public static activity called popBackStack() in my Activity which i call from Fragments to pop the backstack. I am also saving the data from FragmentX here (if the current fragment being popped is FragmentX). Once the Fragment being popped is popped i am checking if the new Fragment is FragmentX, and filling in the data if it is...
Long winded approach but i couldn't figure out any other reliable way. This is working perfectly.
I suggest following guidelines that Google provides and implement an interface declared in your Fragment and save the Bundle or whatever object you want in the activity. Then, in your newInstace() static factory method pass that Bundle and recreate data as usual. Since you are using a ViewPager and it will always render the second fragment before the button is pushed (I assume your second fragment is in another tab) you still need to manage it via an interface. When the back button is pressed, the data will still be there, unless it is destroyed, and you still need to implement onSaveInstaceState() for that matter. You can also use setRetainInstance(boolean retain). See here for more details
If an activity having 3 fragments a, b,c.we are moving from fragment 'a' to fragment 'c, and add to back stack. then press hardware back button, then what are the things being happen.Can any one explain the flow.which destroys first(activity or fragment), the flow which they go through like fragment onpause(), onstop(),... then activity onPause(), onStop() is it?
Fragment always create as last and as first is destroyed.
You can see all this information on this site:
http://developer.android.com/guide/components/fragments.html
information about Activity:
http://developer.android.com/reference/android/app/Activity.html
Imagine the following scenario:
Push Fragment A onto BackStack
Push Fragment B onto BackStack
Push Fragment C onto BackStack
Fragment B tries to make a async web request when its onResume is method is called.
Fragment C has a button called "Clear Backstack" that clears the backstack by calling popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE).
When PopBackStackImmediate is called it pops the Fragments off one by one until the stack is cleared. As each fragment is popped the fragment's onResume method is called. For Fragment B, I don't want the async web request to trigger since its going to be immediately destroyed/removed after its popped (because the entire backstack is being cleared).
In this case how can I detect if the entire backstack is being collapsed and skip the async web request on Fragment B in the OnResume method? Note: I'd still want the async web request to execute if Fragment B is popped/displayed by using the Back button.
Note: I'm using the latest compatibility/support library.
Option 1:
Have you determined what other lifecycle methods are being called - if it's only on resume, then move the async call further down in the lifecyle (onCreateView or onAttach for example) so that it's only called when moving through it in the normal manner.
Option 2:
When onResume is called you could do a getFragmentByTag on the fragment which has already been destroyed. If this is null you could then assume that the operation in action is the destruction.
This one seems pretty ugly to me.
Option 3:
Have C pass some flag up to the controlling activity (we'll call it Main), move the async call up, and when B wants to do the web request, have it call up to main to do so. If C has set the "I'm Destroying" flag, then don't perform the request.
Update: I was previously removing the old fragment and then adding the new fragment using FragmentTransaction.remove and FragmentTransaction.add respectively. Switching to FragmentTransaction.replace solved most of my problems when working with the backstack. See below:
The Android documentation has this to say about FragmentTransaction.replace:
Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.
I found the documentation to be slightly misleading because there is an important difference between replace vs. remove+add when the backstack is involved:
If the backstack A->B->C is built using remove+add, then popped back to fragment A, then fragment B's onResume method will be triggered.
If the backstack A->B->C is build using replace, then popped back to fragment A, then fragment B's onResume method will NOT be triggered.
I have two fragments,
fragmentA in foreground
now I show fragmentB with FragmentTransaction.add(id, Fagment), (not .replace) so the fragmentA is still alive, with fragmentB on top of it,
now I use back button, here the fragmentB is destroyed, leaving fragmentA visible,
at this moment, how would I know that fragmentA has returned to the "foreground", ie onResume,
note that onResume is not called, due to FragmentTransaction.add(id, Fagment), in other words, fragmentA doesn't go onPause when fragmentB is shown
thank you very much for your help
If you want to know when fragment A becomes visible again, you can first hide it in the fragment transaction that creates fragment B:
fragmentTransaction.add(id, fragmentB).hide(fragmentA).addToBackStack(null);
Then in Fragment A, override onHiddenChanged:
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
// Handle visibility changed. Note this method is called only when the state is changed.
}
When the back button is pressed, the fragment transaction will be reversed and the fragment's state will be changed to visible. One thing you have to watch out for: I've noticed that the hidden state isn't preserved between activity rotation so you'd have to perform your own bookkeeping in onSaveInstanceState. I do something similar to what you're asking since in my case the fragment views are expensive to recreate.
Before doing this though, you might want to consider handling your fragments another way, like with .replace() instead of .add(). If your fragment is completely hidden by the new fragment, then maybe you don't need to keep it around, and you can let the fragment manager bring it back once the user hits the back button. That way, you can just use the normal lifecycle functions like onPause and onResume.