I have an activity that is defined in the manifest as:
android:launchMode="singleInstance"
Now I want to move to that activity from a different activity that has no idea that it exists (no reference to the existing instance) and at the same time to pass in a variable. I used to do this like so (before I defined it as singleInstance):
Intent intent = new Intent(this, receivingactivity.class);
intent.putExtra("somekey", somevalue);
startActivity(intent);
But now that doesn't work anymore. I put in the receiving activity the following lines in onresume:
String somevalue = getIntent().getStringExtra("somekey");
and it returns null. How can I pass a value to the existing receiving activity (which is always active and never gets to ondestroy but maximum to onpause)?
You need to use onNewIntent(Intent intent) to retrieve intent passed to it if the activity's launch mode is singleInstance and provided it's not destroyed.
Do not be confused with getIntent() for this one retrieves intent passed on the activity's creation.
Related
This is a bit weird.
I create an Intent in ClassA
Intent notifcationIntent = new Intent();
notifcationIntent.setClass(context,MyClass.class);
notifcationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
String dbgTimestamp = new Long(System.currentTimeMillis()).toString();
notifcationIntent.putExtra("dbgTimestamp",dbgTimestamp);
I log dbgTimestamp after its been created and it has a value of 1000
In MyClass.class I receive the Intent, log dbgTimestamp (which shows me the exected value of 1000) and exit. I have verified MyClass.onDestroy() is being executed.
So far so good.
Then ClassA executes again and build another Intent
Intent notifcationIntent = new Intent();
notifcationIntent.setClass(context,MyClass.class);
notifcationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
String dbgTimestamp = new Long(System.currentTimeMillis()).toString();
notifcationIntent.putExtra("dbgTimestamp",dbgTimestamp);
I log dbgTimestamp after its been created and it has a value of 2000
MyClass executes again, receives the Intent but according to the log dbgTimestamp STILL contains 1000
I don't understand why.
MyClass is being destroyed, and even if it wasn't it contains onNewIntent() for which the docs say:
"This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent). In either case, when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it."
but onNewIntent() is NOT being executed.
I'm a bit at a loss as to what's going on and how to correct it.
Say I have
Intent secondPage = new Intent(FirstPage.this, SecondPage.class);
Intent thirdPage = new Intent(FirstPage.this, ThirdPage.class);
if(i == 2)
startActivity(secondPage);
if(i == 3)
startActivity(thirdPage);
Are either Intents started if the 'startActivity' method is not called?
Or are Intents only started when the startActivity method is called with that Intent as a parameter
See this link
To quote
To start an activity: An Activity represents a single screen in an
app. You can start a new instance of an Activity by passing an Intent
to startActivity(). The Intent describes the activity to start and
carries any necessary data. If you want to receive a result from the
activity when it finishes, call startActivityForResult(). Your
activity receives the result as a separate Intent object in your
activity's onActivityResult() callback. For more information, see the
Activities guide.
As you question stands, if i is not equals to 2 or 3 then these activites will not be started.
If you not call the startActivity, than the Intent won't start the Activity
To answer your question: No.
An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity.
When you say,
Intent secondPage = new Intent(FirstPage.this, SecondPage.class);
The constructor used here takes two parameters:
A Context as its first parameter (this is used because the Activity class is a subclass of Context)
The Class of the app component to which the system should deliver the Intent (in this case, the activity that should be started)
And,
startActivity(secondPage);
To start an activity, call startActivity() and pass it your Intent.
So when you call startActivity(intent)-- there is no intent which is started. The system receives this call and starts an instance of the Activity specified by the Intent.
Read:
http://developer.android.com/training/basics/firstapp/starting-activity.html
http://developer.android.com/reference/android/content/Intent.html
And in your case, if i is not equal to 2 or 3, nothing happens.
Inside a broadcast receiver I want to start my app (Activity) and pass in some data.
My problem is that the extras don't seem to carry over into the activity. I am trying to get the data inside the onNewIntent(Intent i) function.
Any ideas?
Here is my current attempt in the BroadcastReceiver:
Intent intSlider = new Intent();
intSlider.setClass(UAirship.shared().getApplicationContext(), SliderMenuActivity.class);
intSlider.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intSlider.putExtra("action", ScreensEnum.Object);
intSlider.putExtra("objectId", objectId);
intSlider.putExtra("objectCode", objectCode);
intSlider.putExtra("userId", userId);
UAirship.shared().getApplicationContext().startActivity(intSlider);
EDIT - Added code used in onNewIntent() and onCreate()
The following code works great in onCreate() when the app isn't currently running. For when the app is already running the same code doesn't work (i.e. no extras) from the onNewIntent() function.
Intent intent = getIntent();
if(intent.hasExtra("objectId")) {
loadDetail(intent.getStringExtra("objectId"), "2w232");
}
The problem is getIntent() method. It always returns the intent that started the activity, not the most recent one. You should use intent that was passed to onNewIntent method as an argument.
We stumbled upon this problem once, when we were trying to launch/call onNewIntent on an Activity in response to a local notification tap. The extras that we put on our Intent were disappearing at the time onNewIntent received it.
I don't remember this being documented anywhere back then, but the "problem" was that we weren't setting the action field on the Intents that we prepared. Turns out if the Intent received by your Activity doesn't have an action set using setAction, the system still delivers the Intent to its destination, but doesn't transmit the extras you have set while creating the Intent.
TL;DR:
If you encounter this problem with an Intent with no action, calling setAction to set an arbitrary action value before sending the Intent might fix it.
Extract from the docs
This is called for activities that set launchMode to "singleTop" in
their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag
when calling startActivity(Intent). In either case, when the activity
is re-launched while at the top of the activity stack instead of a new
instance of the activity being started, onNewIntent() will be called
on the existing instance with the Intent that was used to re-launch
it.
An activity will always be paused before receiving a new intent, so
you can count on onResume() being called after this method.
Note that getIntent() still returns the original Intent. You can use
setIntent(Intent) to update it to this new Intent.
I think the last paragraph explains your problem.
You have to set the flag FLAG_ACTIVITY_SINGLE_TOP or set launchMode singleTop in the manifest file.
Of course when onNewIntent is called you do not use getIntent but the Intent received as argument.
onNewIntent will be called when the activity instance already exists. For example, if last time you pressed the Home Screen button.
I wrote a solution that worked for me here: Intent with old extra in onCreate() for singleTask Activity
You can store the last received intent in a member variable (mLastIntent).
Then you can use this member in your onResume() method to query for your extra data.
private Intent mLastIntent;
#Override
protected void onNewIntent(Intent intent) {
mLastIntent = intent;
};
I have an activity called HomeActivity that has a SurfaceView and shows a camera preview picture. This activity is quiet heavy and feels slow if you are starting/restarting it.
So I made some investigations and found out, that somehow always the onCreate method is being called. In my opinion this should not happen if the Activity has already been started?
The documentation says :
Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one.
Always followed by onStart().
Here is the method, that handles going back:
protected void gotoHome() {
final Intent intent = new Intent(SomeOtherActivity.this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
Edit:
Here is how I am leaving HomeActivity ... nothing special:
final Intent i = new Intent(HomeActivity.this, SomeOtherActivity.class);
startActivity(i);
Yes, when you want to return to the HomeActivity, you need to use these flags:
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
Here's the relevant section from the documentation on Intent.FLAG_ACTIVITY_CLEAR_TOP:
The currently running instance of activity B in the above example will
either receive the new intent you are starting here in its
onNewIntent() method, or be itself finished and restarted with the new
intent. If it has declared its launch mode to be "multiple" (the
default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same
intent, then it will be finished and re-created; for all other launch
modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be
delivered to the current instance's onNewIntent().
I am intercepting sms messages with some information in them. Then in my SmsListener I'm creating notification to show in statusbar.
Then, when user clicks on a notification I want
Bring MainActivity to foreground (If such activity does not exist yet it should be created)
Pass to it data from the sms
Perform some ui changes basing on this data in this MainActivity
My activity is defined as
<activity
android:name=".MainActivity"
android:screenOrientation="sensor"
android:label="#string/app_name"
android:launchMode="singleTask"/>
Activity is launched as
Intent i = new Intent();
i.setClass(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
Also in my activity I have overridden method onNewActivity
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
// I have data from broadcast in intent variable passed to this activity
processDataFromBroadcast(intent);
}
It works fine if the MainActivity already exists but if MainActivity does not exist it is started however onNewIntent was not called
Then I tried to invoke processDataFromBroadcast from onCreate: processDataFromBroadcast(getIntent()).
First time data is passed correctly from my broadcast to the activity.
However if MainActivity is sent to background and then again brought to foreground either onCreate or onNewIntent is called and processDataFromBroadcast is executed again with intent sent by broadcast and thus my MainActivity is updated with data from broadcast every-time the app is bringing to foreground - the latter is unwanted, how can I make my activity to forget this intent after first handling.
Here is sample application.
For an activity to launch only one instance of itself, have a look at the <activity> manifest element, and particularly android:launchMode. You want to configure it with either singleTask or singleInstance.
To pass data to your activity, you add data to the Intent you use to open it. To pass data with the intent, use the putExtra() methods of the intent before sending it off, and getExtra() methods to retrieve them in your receiving activity.
I'm assuming that you know roughly how intents work, but if not you could learn more about intents by taking a look at this Android developers article.
in case your problem is still unresolved, as I was just running into the same issue, here's how I solved it:
I am putting a timestamp as intentId as an extra upon the intent during it's creation. the first time, I am handling the intent in onCreate() or onNewIntent() I am reading the intentId and store it as the last intent handled. so the next time onCreate() or onNewIntet() is invoked I can check the intentId and if it equals the id of the last intent handled, I ignore it! It don't know if this helps in your case, maybe you can adopt it.
To keep intentId independent from activity lifecycles you could persist it in the userdefaults.
I agree that one would expect calling setIntent(new Intent()) in onNewIntent should do the trick.
It it late to answer, but it might be helpful to others looking for the solution.
Just add below lines of code :
Intent mIntent = new Intent(this, SplashActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // You need this if starting the activity from a service
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Where SplashActivity is the name of initial application that is the first screen of your application.
Hope it helps. :)