Im wondering how long does getIntent() in a Activity will be available (does not return null). So lets say I start Activity B from my Activity A and pass some extra data in the Intent.
In Activity B I will read the extra data from the intent in the activities onCreate() method.
So far so good. But how long is getIntent() available? I mean, if the user is displaying Activity B, but switchs to another App (i.e. by using the multitasking button) and after some hours the user clicks on the multitasking button again (the activity may have been destroyed in the meantime) and opens Activity B again. So Activity B onCreate() will be called to reinstantiate the Activity B. Does getIntent() now still returns the original Intent with the extra value or do I have to save the Intent extra value in Activities onSaveInstanceState() and use the Bundle in onCreate(Bundle state)?
Does getIntent() now still returns the original Intent with the extra value
Technically, it returns a copy of the Intent. Generally speaking, it should be identical to the original Intent, including all extras.
From Android doc, getIntent() return
Return the intent that started this activity.
But their are so many case where getIntent is null or extras are null. Check this link and this. Specially on device rotation or from pressing back keys.
But as its seems documentations says otherwise. Just to be in safe side, i will recommend you to do following
if (getIntent() != null && getIntent().getExtras() != null){
}
And, your activity code should prepared to handle the scenario where getIntent is null.
Related
If Activity A calls Activity B with .setExtra(someKey, someValue), and Activity B calls Activity C, from which the user returns to Activity B with the back button, can Activity B still access the Extras from Activity A?
A
A -> B (with Extra)
A -> B -> C
back button pressed
A -> B (with Extra?)
Is the Bundle persisted or discarded in this scenario?
I could not find this in When do intent extras become null between activities? and Android Intent Extras Sticking Around
In ActivityB when calling getIntent() you will always have access to the "extras" that were sent in the Intent that started ActivityB. Android persists the Intent (including "extras") so that even if Android kills the process (because the user put it in the background), when the user returns to the app, Android creates a new process and recreates the Activity with the original Intent.
No, they do not always persist. Most of the time, it works, but sometimes, the extra was just null, which created a NullPointerException upon accessing it. So there is no guarantee that the system keeps the Extra. Better save it somewhere.
I have an activity A which starts a new activity B with startActivityForResult.
Activity B is restarted several times with FLAG_ACTIVITY_CLEAR_TOP, so when the user clicks on back, B puts on data with setResult() and comes back to Activity A. However, the data is missing. onActivityResult in A is invoked with intent to null and resultCode by default.
I know that, in fact, is the right behaviour since FLAG_ACTIVITY_CLEAR_TOP discards previous activities, but I wonder if there is some workaround to achieve this (apart from obvious options like avoiding restarting B)
Add both FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP to your launch intents when you restart Activity B.
activityBIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Also relaunching Activity B will call onNewIntent(Intent), however getIntent() will still deliver the older (original) intent.
Note that getIntent() still returns the original Intent. You can
use setIntent(Intent) to update it to this new Intent.
In my main activity I want to override the onResume method so it acts differently, depending on the activity, which was opened before.
For example: if the user creates a new Item for the listView (in the addNewItem activity), I need to reload the database to display the newItem.
But if he just switches into an activity, which doesn't change anything with the objects displayed in the main activity, the database shouldn't be reloaded and the GUI shouldn't be build again.
Therefor I need to know which activity was 'opened' before.
I hope you understand my problem.
A dirty way is to extend your application class and set an attribute lastActivity that you would set in every onResume/OnPause methods of every activities in your app. This way, when your main activity on resume is called, just read this lastActivity field to know where you come from. But I think it's the dirty way to do it :D
You can send something through in your intent when you call the Activity.
Intent myIntent = new Intent(Activity1.this,Activity2.class);
Bundle myData = new Bundle();
myData.putString("previousActivity", "Activity1");
myIntent.putExtras(myData);
startActivity(myIntent);
Then in the new Activity, you access this and compare the result:
Intent myLocalIntent = getIntent();
Bundle myBundle = myLocalIntent.getExtras();
String str1 = myBundle.getString("previousActivity");
if string.equals("Activity1"){
// do code changes for activity 1 here
}
There are slightly more refined ways of doing this (i.e passing through an int variable which corresponds to a particular Activity) but this is the most basic way.
The right way to do it, is to start every activity with startActivityForResult(intent, resultCode).
When an activity exits, it can call setResult(int) to return data back to its parent.
Link to Developers Resource
I have an Android application that contains two Activities.
Activity A has a button that launches Activity B using Context.startActivity(Intent intent).
There is also a Notification that opens Activity in the same way.
If I start B from this notification and press back button - it just closes B and does not shows A like I go there with normal case.
Is it possible to force B to bo back to A if started from notification without history stack ?
Solution
As stefan and Paul Lammertsma mentioned, the best way is to start A from notification and in A create new intent with B - but not in onCreate() !
I dig this a bit and found that if I set in AndroidManifest a new property for A activity:
android:launchMode="singleTask"
there will be in A activity called
onNewIntent(Intent intent)
And there we should checl if Intent containst extra value passed from notification - and if so, then we call new B intent.
Thank you both and good luck with it for next devs ;-)
I would suggest having the notification call Activity A (instead of B directly) with some flag in its extras bundle. In A's onCreate(), check for the flag, and immediately launch Activity B. This will ensure that pressing back on B will return to A.
An easy way to achieve this would be to actually start Activity A from your Notification with a flag to call Activity B instantly.
So you just have to put an extra to your intent you are starting in your Notification and you have to check in Activity A if this extra exists and if it exists then you start Activity B.
Update: another way, but in my opinion not so good, would be to override the onPause() method of your Activity B and call Activity A there.
Maybe not the prettiest solution, but nevertheless a quick one;
add a boolean extra to the intent launching B, "launchedFromNotification" or something like that.
In activity Bs onCreate() you store that boolean value for later use.
In activity Bs onBackPressed() you can check the value of your boolean and if true, launch activity A before calling finish();
A prettier solution may be to launch activity A from the notification, with an extra telling it to directly launch activity B.
I have the following scenario (note that activity A has launchMode="singleTop"):
Activity A calls startActivityForResult() on activity B;
Activity B calls startActivity() on C, after which setResult(RESULT_OK) and finish(); at this point, onActivityResult() in A is NOT called.
Activity C calls startActivity() on A using FLAG_ACTIVITY_CLEAR_TOP and finish();
This is where my problem occurs. At this point, A's onActivityResult() is called with the right requestCode, but something else than RESULT_OK as the resultCode. I was expecting it to receive RESULT_OK because I have set it in B (which was started for result).
Why am I getting something other than RESULT_OK?
Read this doc:
http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched
is already running in the current
task, then instead of launching a new
instance of that activity, all of the
other activities on top of it will be
closed and this Intent will be
delivered to the (now on top) old
activity as a new Intent.
Passing clear top flag will finish all activities in the stack. So what you'll get in onActivityResult is probably a "notification" that the activity for which you want the result was canceled. (aka RESULT_CANCELED = 0x00)
UPDATE
When I use startActivityForResult, after setting the result, I always finish my activity and let the caller come to action.
You are doing something less common: you set the result, finish your activity but you also start another one. I don't know is the expected behavior in this situation. Can't you change the interaction between the activities?
You could try to call finish() first and then start the new activity (do this in activities B and C). Anyway, I also don't know what should happen when you do this. I recommend you the first approach (changing the interaction so you don't return a result and create a new activity at the same time).
Perhaps you could chain two startActivityForResult or your activity B could send a new intent to A instead of returning its result?