The launcher activity of my app is defined with this intent-filter
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
I specified the launchMode for this activity as singleTask.
According to the second answer of this question - Android default launchMode of LAUNCHER activity? it shouldn't make any difference. But in my case every time I minimise the app and then relaunch it using the app icon the LauncherActivity is being brought to the forefront with intent flags - FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_RESET_TASK_IF_NEEDED and FLAG_ACTIVITY_BROUGHT_TO_FRONT. This is causing the LauncherActivity to start on top of the existing task.
While for standard and singleTop launch modes there is no problem. The LaunchActivity is not being instantiated again.
Is this an anomaly or am I somewhere wrong in my understanding?
Related
The following situation:
app is started from a deep link (sms) and launches the MainActivity
user presses the start button in the app which opens SecondActivity
app goes into background
user presses on app icon again in launcher => HERE I EXPECT the SecondActivity be still active. But instead, MainActivity is relaunched.
Tried with "singleTop" activity mode - no difference.
SecondActivity is launched from MainActivity without any special intent flags, plain startActivity()
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:alwaysRetainTaskState="true"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE”/>
It turned out there are two reasons:
Starting app from deep link created separate instance of the app => solved by specifying "singleTask"
The SecondActivity was destroyed at some point, which explains why starting the app again from icon will bring MainActivity screen
Thanks all commenters for helpful hints!
When starting the secondActivity you can just call finish() in the firstActivity (for example in onPause() or buttonClick() firstActivity). In this way, your app is still running (i.e secondActivity). When you launch the app the secondActivity should run directly (if the app is not totally destroyed yet).
My application have two activities, say MainActivity and SecondActivity. Main activity is declared as android:launchMode="singleInstance" and its orientation is always portrait. Second activity is always has landscape orientation.
In some devices, everything is alright and in task manager there is only one instance of my app, but in some devices (like Samsung S7), when I launch SecondActivity, there will be two instances of my app in task manager like this image:
My guess is that something is wrong with the launchMode of the MainActivty but I need it to be singleInstance. Any suggestion?
EDIT:
MainActivity in manifest:
<activity
android:name=".Activities.MainActivity"
android:screenOrientation="portrait"
android:launchMode="singleInstance"
android:theme="#style/AppTheme"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
and second:
<activity
android:name=".Activities.SecondActivity"
android:screenOrientation="landscape" />
launching code:
Intent intent = new Intent(getActivity(),
intent.putExtra("VideoUri", filmGet.getOutput().getData().getFilmTrailer());
startActivity(intent);
If it helps, I launch SecondActivity from a fragment.
So, after reading #sharan comment and some googling, it made me to read some google documents. According to docs, there isn't any difference between android:launchMode=singleInstance and android:launchMode=singleTask but one. They both make your activity singleton and so you will never have two instances of it. The only difference between them is that singleInstance will prevent the task from attaching any other activity while singleTask has not this limitation. Any other things about them are the same.
So, for anyone who is reading this post, I'll recommend you to never use singleInstance launch mode unless you exactly need what it has. Because if you have only one activity in your app, then there will be no differences between singleInstance and singleTask. And if you have more than one activity, then I'll recommend you to all of your activities belong to one task.
In short, change singleInstance to singleTask and you are go.
I have 2 activities: Activity A and Activity B. Activity A's launch mode is standard, and Activity B's launch mode is singleTask.
<activity
android:name=".AActivity"
android:label="#string/app_name"
android:launchMode="standard">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="dd"></data>
<data android:host="a"></data>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
<activity
android:name=".BActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="dd"></data>
<data android:host="b"></data>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
I launch the app, and the launcher Activity A starts. Then i press Home Button and return to home screen of the phone. Then i launch browser app and type the following:
dd://b
to open Activity B. The system navigates to my App and starts activity B on top of activity A. At this point if i press back button, activity B is popped and i see activity A.
This is not what i expected because the android documentation states:
For singleTask activities, the system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method, rather than creating a new instance. Only one instance of the activity can exist at a time.
What i understand from these sentences is, in my case since an instance of Activity B does not exist, a new task should have been launched and it should have had only Activity B at its stack(Another instance of my app should still exist in a separate task and it should have Activity A in its stack). Then if i press back while i was at Activity B, since it is the only activity in the backstack, it is popped out and the system returns to the browser.
Why this is not the case? How does android system know that my app is open and navigates to it and starts activity B on top of existing app stack instead of launching another instance of my app and letting two instances of my app have their own stacks? What does it mean to instantiate activity in a new task? Can anyone explain?
Thanks.
In addition to the accepted answer, I found an explanation to this problem. As android documentation states:
The affinity indicates which task an activity prefers to belong to. By default, all the activities from the same application have an affinity for each other. So, by default, all activities in the same application prefer to be in the same task which belongs to that app(The app that has the Activity B). However, you can modify the default affinity for an activity.
So, if your app is running, and you start an activity, which has launchMode:singleTask attribute, unless you explicitly state taskAffinity attribute, it starts the activity in the same task. But if you explicitly state an affinity in your manifest:
<activity
android:name=".BActivity"
android:label="#string/app_name"
android:taskAffinity=""
android:launchMode="singleTask">
</activity>
then it starts the activity in a new task.
You can see which activity belongs to which task by the following adb command:
adb shell dumpsys activity
and also, to better understand launchMode concept, you can see the following app in the Google Play: https://play.google.com/store/apps/details?id=com.novoda.demos.activitylaunchmode
You said that your app navigate to B in passing by A.
So, i think you have two stack. In the first, you have only A, in the second you have only B. If you press back, then B is popped and disapeared but A exists and is showing because A in behind B even if A and B are in separate stack.
If you want that B pop and then you return to home, try to call "finish()" after call B from A
I'm developing custom launcher app containing a WebView. When I launch app as a normal app, it works without any issues, after calling startActivity()/ startActivityForResult() (Intent.ACTION_CALL, doesn't occur when using Intent for MediaStore.ACTION_IMAGE_CAPTURE) application calls onPause(), onStop() and other activity starts, after completing its task goes back to the application. However when I set application as launcher, it calls onDestroy() right after onPause() and onStop(). Such behaviour is not desired because I'm trying to keep inserted data in the launcher WebView app.
There are also many errors in logcat right after onDestroy() similar or same as E/libGLESv2﹕ HWUI Protection: wrong calling from app context F:ES3-glDeleteBuffers (when not using it as launcher such errors appear, but sporadically and in different situations).
AppManifest contains
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I also tried using singleInstance, with that mode application works correctly after installation, but breaks its behaviour after restart.
Using minSdkVersion 19, tested on Android 4.4.2.
Ok, so here's how I managed to solve the issue, and actually what was the problem. I used
Settings.System.putInt(
getContentResolver(),
Settings.System.USER_ROTATION,
// toRotate //Or a different ROTATION_ constant
Surface.ROTATION_270
);
for screen rotation, because I needed to be sure the app was running in landscape mode. The thing is, camera supports landscape mode, but dialer doesn't. So when I launched camera it was without issues, but dialer caused portrait rotation and that caused WebView's default behaviour when rotating the screen, onDestroy() and that causes reload afterwards...
Let begin by changing it to something like this,
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Now lets understand what launchMode(s) are
via the documentation:
android:launchMode
An instruction on how the activity should be launched. There are four modes that work in conjunction with activity flags
(FLAG_ACTIVITY_ constants) in Intent objects to determine what should
happen when the activity is called upon to handle an intent. They are:
"standard" "singleTop" "singleTask" "singleInstance" The default
mode is "standard".*
"singleTask" Does not allow Multiple Instances 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.
"standard" Default. The system always creates a new instance of
the activity in the target task and routes the intent to it.
"singleTop" If an instance of the activity already exists at
the top of the target task, the system routes the intent to that
instance through a call to its onNewIntent() method, rather than
creating a new instance of the activity.
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.
For more in depth refer to the Documentation
In my application there is a behavior that I don't understand. I have the MainActivity A as SingleTask.
It calls an Activity B that is SingleTask too.
When I press the Home button in the second activity to open another application, and after that I try to go to my application mantaining Home button pressed i always go to Main Activity, and I want second activity to be opened mantaining the state that had when i press Home button.
I've tried setting then second activity to singleTop and it doesn't work.
Any help?
The behaviour of activity back stack becomes quit weird when define main activity with singleTask at the same time:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
What even worse is there is no clear explanation in the official dev guide regarding to this special use case. Some sections related to this topic are even self-contradictory.
Try using launchMode="standard" on your MainActivity A, and launchMode="singleTask" on your Activity B, which will give the expect behaviour you described.