I have a MainActivity and inside it, I am loading a fragment A. From FragmentA , I am calling google placepicker activity using startActivityforResult as follows.
PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
Intent intent = builder.build(getActivity());
getActivity().startActivityForResult(intent,PLACE_PICKER_REQUEST);
But when I select place, onActivityResult(either in FragmentA or MainActivity) is not getting called. In fact,my application is getting destroyed after startActivityForResult call.
As per my understanding, android should recreate the calling activity if it is not available in memory.But it is not happening.Even onCreate is not getting called inside MainActivity.
Could anyone tell me the reason behind this kind of behavior or am I missing anything?
Now instead of PlacePicker Activity, I have tried using another activity in same application.
Let's say I have MainActivity
with FragmentA
loaded.I am calling SubActivity
with startActivityForResult
from FragmentA
.Now while returning from SubActivity
,the application exits. I have enabled Dont keep activities
in my device to test this specific scenario. I can see MainActivity
getting destroyed when I move to SubActivity
.But on returning from SubActivity
, android is not recreating MainActivity
(even onCreate
is not getting called.The application just exits).
This can happen due to many reasons, but hopefully it's a rare occurrence. The OS will destroy the Activity when backgrounded if it needs to reclaim resources, which is more likely to happen on devices with less memory and processing power.
Using the
Do not keep Activities
setting is a good way to test this scenario, and in this case there are other problems even if the Activity/Fragment do get re-created. With this setting enabled, the Activity and Fragment do get destroyed when the PlacePicker is shown, and then whenonActivityResult()
comes in, there is no valid Context because the Activity and Fragment are still in the process of being re-created.I found this out by performing a controlled test with the setting disabled, and then with the setting enabled, and then looking at the results
I put logging in each lifecycle callback for the Activity and the Fragment in order to get an idea of what is going on during these calls.
Here is the full class I used that includes both the Activity and the Fragment:
Here are the resulting logs that give insight into what lifecycle callbacks are called during the process under normal circumstances:
So, as you can see
onDestroy()
is never called, andonPause()
andonResume()
are called on both the Activity and the Fragment.Here is the result visually:
Then after picking a place:
Then, I enabled
Do not keep Activities
under Developer Options in Settings, and ran the same test.These are the resulting logs:
So, you can see both the Activity and Fragment are destroyed when the PlacePicker is shown, and after the place is picked in the PlacePicker, the code execution never got to the
Fragment processActivityResult
log entry, and the app never showed the picked place on the map.That is because of the null Context check:
So, the call to
onActivityResult()
does come in, but it does so at the same time that the Activity and Fragment are getting re-created, and you need a valid Context to make the call toPlacePicker.getPlace(data, getActivity());
.The good news is that most end-users will not have the
Do not keep Activities
setting enabled, and most of the time your Activity won't be destroyed by the OS.It seems quite unusual for Android to clean up an activity in the way you described, but if that was the case then your activity should still be restored. Android should not destroy the activity, unless you specifically call
finish()
or something causes the activity to end prematurely.If you refer to the activity lifecycle diagram:
In the scenario you described the first activity should call onStop, but not onDestroy, then when you return from the second activity it should call onStart again.
I created a very simple app to test the scenario you described, which contained the following:
startActivityForResult()
ActivityLifecycleCallbacks
in a custom application classonActivityResult
additionally outputs to the log when it gets calledHere is what is output:
Application is started (FirstActivity is created and started and visible):
I press the button to start SecondActivity:
Note, onDestroy does not get called.
Now I press the back button and return to the first activity:
The back button calls
finish
on SecondActivity so it's destroyedNow if I press back again FirstActivity will also be finished, causing
onDestroy
to be called.You can see that this example has adhered to the lifecycle diagram exactly. The activities are only destroyed once the back button is pressed, which causes the activity to call
finish()
.You mentioned that you tried turning on "Don't keep activities" in the developer options, we can repeat the above experiment which this option enabled and see what happens. I have just added the relevant lifecycle events to save repeating everything that is above:
After pressing the button in the first activity to start the second activity:
As expected, the activity has been destroyed this time. This is what happens when you navigate back to the first activity again:
This time onCreate was called again as the system didn't have a stopped version of the first activity to restart. Also
onActivityResult()
was still called, regardless of the fact that the activity had to be recreated.This further supports that something in your first activity must be calling
finish()
or causing it to crash. However, without seeing your actual code this is conjecture.Finally, to maintain state if your activity does for some reason need to get recreated, you can override
onSaveInstanceState()
and add any state information to the bundle:When the activity is recreated, you'll get a bundle back in onCreate which should contain everything you saved: