I have fragment A, which calls fragment B with setTargetFragment.
Once fragment B finishes certain operations, it calls getTargetFragment().onActivityResult().
It works fine(meaning, fragment A's callback onActivityResult is being invoked as it should) , but fragment B is not detached or removed. The user still stays on fragment B for some reason. How is that possible? shouldn't oActivityResult remove the fragment from the stack, or at least go away for the user to see fragment A again ?
The process is pretty much the same as in an activity which you need to call finish() after setting the result. In case of a fragment you should call popBackStack() to remove the current fragment, the same way you call finish() to pop the current activity.
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 Activity A, Inside that activity there is one fragment called F1 and inside that fragment i have another fragment F2. From F2 I called startActivityForResult(/Activity B/) and then when finishing activity B. onActivityResult() of fragment F2 is getting called but i want same thing to be happened in F1.
What I want is Fragment F1 should get the event that Activity B is finished.
Any help on this is appreciated.
Hi You need to get the current fragment form Fragment manager in Activity's
onActivityResult() Method.
Just make a call to fragment's onActivityResult() method.
CustomFragment fragment = (CustomFragment ) getFragmentManager().findFragmentByTag(getFragmentManager().getLastBackStackEntry());
fragment.onActivityResult();
You can use this technique.
You are most likely calling StartActivityForResult from your F2 fragment. Since you don't want the result going back to F2, you need to call that method on fragment F1 instead.
It would be nice to see some code to see what you are actually doing.
From your question it seems that F2 is child fragment for F1.
If so you can call startActivityForResult method from fragment F2 as below :
getParentFragment().startActivityForResult(intent, requestCode);
Now, when you will finish the second activity, it will automatically call onActivityResult() method of parent fragment (i.e. Fragment F1).
Android's Fragment's onResume/onPause methods are tightly coupled with the host Activity's lifecycle as shown here.
What I want to know is how to detect that a fragment is left from / returned to inside the app's navigation flow.
Example:
Say I have MainActivity and fragments A,B and C.
MainActivity adds fragment A, then B and then C.
How do I know fragment B was left (I now see fragment C).
Also, once I press on back, how do I know fragment B was resumed?
Edit:
Clarification: I want to know that from within fragment B (similar to the way an Activity works with onPause and onResume)
Try isDetached() method link here
Respectively there is isAdded()
Indirectly you question concern with Fragment LifeCycle.
And you can trace fragment navigation replace,remove,add using Fragment manager
PopBackStack : Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned.
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.