I have two activities with "navigation menu" which has items for launching Activity1 and Activity2.
For example we starts Activity2 from Activity1 and then we want open Activity1 by tap on "navigation menu", but when we do this we get new instance of Activity1 instead of open еxisting instance.
How can i open instance of Activity1 if it already exists and create new instance if not?
Add FLAG_ACTIVITY_REORDER_TO_FRONT to your Intent you use with startActivity().
add android:launchMode="singleTop" to your activity in the Manifest.xml
<activity android:name=".myActivity" android:label="#string/app_name"
android:launchMode="singleTop" />
Check this out about different launchModes
also mind this:
As shown in the table above, standard is the default mode and is
appropriate for most types of activities. SingleTop is also a common
and useful launch mode for many types of activities. The other modes —
singleTask and singleInstance — are not appropriate for most
applications, since they result in an interaction model that is likely
to be unfamiliar to users and is very different from most other
applications
Set the flag of the activity to singleTask and override the onNewIntent(Intent intent) to catch the new intent.
The most complete answer would be to use android:launchMode="singleTask" and depending on your functionality, override onNewIntent since it will be called if there is already an instance of the Activity with the new Intent passed to it.
<activity
android:name=".MainActivity"
android:launchMode="singleTask"/>
Why?
Based on the question.
There are two Activities, Activity1 & Activity2
We open Activity1 and then from Activity1 we open Activity2. Then, inside Activity2:
How can i open instance of Activity1 if it already exists and create new instance if not?
As stated in AndroidManifestActivity_launchMode for singleTask
If, when starting the activity, there is already a task running that starts with this activity, then instead of starting a new instance the current task is brought to the front. The existing instance will receive a call to Activity.onNewIntent() with the...
Furthermore, under the intent class, if you read about the singleTask launchMode it already uses Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT and manually setting an intent to it is not normally set by application code.
As stated in FLAG_ACTIVITY_BROUGHT_TO_FRONT
int FLAG_ACTIVITY_BROUGHT_TO_FRONT
This flag is not normally set by application code, but set for you by the system as described in the launchMode documentation for the singleTask mode.
Therefore, by using singleTask launchMode you ensure that there is only one instance of your application and you do not have to be adding the FLAG_ACTIVITY_BROUGHT_TO_FRONT flag to your intents in every activity which calls your Activity2 as suggested by CommonsWare.
Now, if we use the android:launchMode="singleTop" as weakwire suggested, the link he provided himself clearly states;
"singleTop"...In other circumstances — for example, if an existing instance of the "singleTop" activity is in the target task, but not at the top of the stack, or if it's at the top of a stack, but not in the target task — a new instance would be created and pushed on the stack.
In other words, we would end up with multiple instances of Activity1 in some scenarios which is what we do not want.
As final say, if you are one of those who love editing answers that contribute nothing to the answer itself, go answer some real questions if you really want to increase your Stack Overflow Reputation.
Related
I launch an activity with startActivityForResult() and want to prevent multiple instances from being started at the top of activity stack. So I expect android:launchMode="singleTop" to do its work, but for some reason the flag gets ignored.
After some investigations I managed to launch only one instance by adding FLAG_ACTIVITY_REORDER_TO_FRONT to intent, but I would be grateful if someone could explain me the reason why "singleTop" doesn't work in such case. The code is very simple.
// Activity class
Intent intent = new Intent(this, DetailsActivity.class);
// multiple instances can be launched without this line
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(intent, REQUEST_CODE_DETAILS);
// AndroidManifest.xml
<activity
android:name=".DetailsActivity"
android:launchMode="singleTop"/>
How SingleTop work?
let suppose you have current activity stack like
A->B->C
Now from current activity C, if you start A activity which is a singleTop, so in this case system will create a new instance of A and brings that instance to top. (If specified activity is not on top then new instance will be created)
So stack will look like
A->B->C->A
Now if you try to open A again then in this case as A on top already, so NO new instance will be created. Instead A will receive callback in onNewIntent() method
Flag
FLAG_ACTIVITY_REORDER_TO_FRONT
it scans from the front of stack to back of stack and if it found instance of specified activity then brings that activity to front.
So in your case if DetailsActivity instacne is already present in system then this flag will bring DetailsActivity to front
The flag FLAG_ACTIVITY_SINGLE_TOP must be ignored in this case because when you launch an Activity using startActivityForResult() you are basically saying that you want to launch an Activity and have the Activity return you a result.
If an instance of this Activity already exists in the stack (regardless of where it is in the stack), that instance has not been setup to return a result to your Activity. It is possible that that instance was launched using startActivity() in which case it isn't setup to return a result at all. It could be that it was launched using startActivityForResult() from another Activity, in which case it is set up to return a result to the Activity that launched it, not to your Activity.
These 2 things: FLAG_ACTIVITY_SINGLE_TOP and startActivityForResult() therefore are in conflict.
I am trying to add upload image feature in my application, using android-upload-service.
I am facing a issue not specific to the library.
When i am clicking on upload notification I want to open a activity using Intent.
code:
val intent = Intent(context, EditorActivity::class.java)
intent.putExtra("ResourceId", resourceId)//No I18N
context.startActivity(intent)
But,
First requirement is to start activity if it's not onScreen.(i.e application might be dead, or i might be on different activity)
Second if the activity is already running then do nothing
How can i check is the specific activity is dead or running and on Screen.
current code is starting the activity on top of present activity because of what i am having same activity on top of each other.
Add launchMode="singleTop" to the <activity> definition in the manifest. That should be enough to do what you want. It tells Android that it should use an existing instance of the Activity instead of creating a new one, if an instance of that Activity already exists at the top of the activity stack in the task.
Please don't use one of the special launch modes singleTask or singleInstance as these usually create more problems than they solve if you do not know exactly what you are doing.
First, add android:launchMode="singleTask" for that activity in your AndroidManifest.xml file. This will make sure that there is only one instance of the activity at all time.
Example,
<activity
android:name=".activities.MyActivity"
android:launchMode="singleTask"/>
I want to keep a single instance of every Activity I start in my application. The launchMode singleTask was an option but it is working for only one Activity.
I want
to start an Activity if there is no instance and it is called.
and if any other instance of that Activity is present already then
that instance will brought to front without creating a new instance
of that Activity.
This property will be applied to more than one Activity.
No Activity does guarantee that it will be always on the top of the history stack.
My work until now:
I got many suggestions which are not valid for my case, so I want to point these out so that no other person would give the same suggestion.
I have set the launchMode to singleTop and this works only if the Activity is at the top of the history stack. onNewIntent() only gets called if Activity is at the top of history stack. and in my case the Activity may be at any position in stack. So this is not working.
When you launch an Activity, do it like this:
Intent intent = new Intent(this, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
If an instance of this Activity already exists, then it will be moved to the front. If an instance does NOT exist, a new instance will be created.
You can set the android:launchMode of your activity to singleTop
In this case the if the activity already exists, new intents will bring it to front will be delivered to the activity's onNewIntent()
http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
This will work if your activity is on the top of the stack.
if you want to have a single instance of the activity, then you can set your launchMode to singleTask, but this is not recommended as it will make your activity reside in a separate task , which can be confusing to the users.
Use singleTop launch mode instead (docs): if there already is an Activity instance with the same type at the top of stack in the caller Task, there would not be any new Activity created, instead an Intent will be sent to an existed Activity instance through onNewIntent() method.
See can also this article for details on launch modes.
I encountered an interesting issue, where an Activity is created multiple times, even it is defined as a singleTask or a singelInstance Activity in the manifest. Here is how this can be reproduced. Say, in the main activity:
#Override
protected void onResume() {
Intent i = new Intent(MainActivity.class, SingleActivity.class);
startActivity(i);
}
in my SingleActivity, I have:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
Log.i("SingleActivity", "onCreate " + System.identityHashCode(this));
...
}
and in the manifest, I have:
<activity android:name=".SingleActivity"
android:launchMode="singleInstance"
/>
now, if I start the application, things seem OK, expect in one case: if I press the 'back' button while SingleActivity is in front, it navigates back to MainActivity, where MainActivity.onResume() will create another SingleActivity instance, instead of bringing forward the one that already exists. this is something I know because on the log, a different identity hash code is displayed.
the same seems to be true if the launch mode is singleTask.
the only workaround seems to be to override onBackPressed(), but that seems like an ugly solution.
I wonder what I'm doing wrong
This is a problem of taskAffinity. Because you haven't specified taskAffinity in the manifest on either your MainActivity or your SingleActivity, these 2 activities have the same (default) taskAffinity. When you start an activity, Android checks the taskAffinity of the activity that you want to start. If it is the same as the taskAffinity of the root activity in your task, then it will ignore launchMode="singleInstance" or launchMode="singleTask" (because those launch modes would require Android to create a new task to launch the activity in) and start the activity in the current task.
Unfortunately, this isn't well documented, but taskAffinity takes precedence over launchMode.
If you really want a singleTask or singleInstance activity (which is usually not the right thing to do because it brings with it a whole mess of other nasty things that you are likely to get wrong), then you need to make sure that your singleInstance or singleTask activity has the following in the manifest in its <activity> definition:
android:taskAffinity=""
If you need more information, search StackOverflow or Google for "launchmode taskaffinity"
By default, pressing the BACK key finishes (destroys) the current activity and displays the previous activity to the user.
So, this is impossible to
instead of bringing forward the one that already exists
because no activity exists.
I have an Activity which is basically my main activity and its launch mode is single instance. But because of singleInstance, the onActivityResult() callback does not fire. And if I change the launch mode in my manifest file to any other mode it works fine.
Can you explain why this callback is not working?
I believe that the problem is that singleInstance doesn't let the callee activity to exist in the same task as the caller, hence it can't return the value to the caller.
Consider using singleTask instead:
singleTask
The system creates the activity at the
root of a new task and routes the
intent to it. However, if an instance
of the activity already exists, the
system routes the intent to existing
instance through a call to its
onNewIntent() method, rather than
creating a new one.
singleInstance
Same as "singleTask", except that the
system doesn't launch any other
activities into the task holding the
instance. The activity is always the
single and only member of its task.
http://developer.android.com/guide/topics/manifest/activity-element.html
If an activity is singleInstance, it will be the only one in the task so it always be the top of the task. So when you call startActivityForResult it will fire the callback method immediately.
A "singleInstance" activity, permits no other activities to be part of its task. It's the only activity in the task. If it starts another activity, that activity is assigned to a different task. The activity is always the single and only member of its task.
I think onActivityResult will not work with singleInstance
You can't use singleInstance or singleTask with startActivityForResult method.
Standard mode or singleTop launch mode will fix the problem.
Android Source Code
Check "ActivityStarter.computeLaunchingTaskFlags()" method:
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
That's the reason why NEW_TASK flag is added when your original activity with single instance launch mode.
More Source Code
Check "ActivityStarter.sendNewTaskResultRequestIfNeeded()" method:
if (sourceStack != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new task...
// yet the caller has requested a result back. Well, that is pretty messed up,
// so instead immediately send back a cancel and let the new task continue launched
// as normal without a dependency on its originator.
Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
null /* data */);
That's the reason why FLAG_ACTIVITY_NEW_TASK always immediately return RESULT_CANCELED.
An example of my application can benefit someone:
In the manifest file, my settings are:
<application android:launchMode="singleTask"...>
I use one java class, only as a launcher(it does not show Activity). In the manifest, it is set to:
<activity android:launchMode="singleTop" ...>
Also, other Activities are set the same:
<activity android:launchMode="singleTop" ...>
When a user sends an application to the background, by clicking on the application icon or restoring the application from the background, the last started Activity is returned unchanged, even though they were all started with startActivityForResult() from launcher.