I have 3 activities: Splash (launcher), Login, Dashboard. When app is opened Splash waits some time and then starts Login, finish
ing itself. Then user can then navigate from Login to Dashboard.
I want to maintain a single instance of the app whenever the user clics on the home button, or is directed towards the app by a browsable Intent. So that the user is returned to where he or she was before switching the app.
The following is the behaviour with android:launchMode="standard"
and singleInstancePerTask
(red squares are finished activities)
singleTask
behaves similar to the additional web intent for standard mode, i can add logic to Splash so that it interrupts processings and finish if it is not root:
Lastly If I choose singleInstance
, the following happens:
This seems to work, but there is something that I don't understand. Why is the second Splash ignoring the Intent to launch Login activity?. The logic tells me that a Login #2 should've launched.
Manifest in matter:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.testintentflags">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestIntentFLags">
<activity
android:name=".SplashActivity"
android:exported="true" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="demo.intents.com"
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name=".DashboardActivity"
android:exported="false" />
<activity
android:name=".LoginActivity"
android:exported="false" />
</application>
</manifest>
There are a number of things going on here, I'll try to address these:
First off, using launchMode="singleInstance"
is problematic here, because you have not declared any taskAffinity
for any of your activities. So your SplashActivity
and your other activities have the same (default) taskAffinity
which tells Android that all these activities want to run in the same task, which conflicts with your launch mode declaration of SplashActivity
. This is bad, and you shouldn't do it. If you really want to have activities running in separate tasks, you should ensure that they have different taskAffinity
so as not to cause confusion.
Secondly, you wrote:
This seems to work, but there is something that I don't understand. Why is the second Splash ignoring the Intent to launch Login activity?. The logic tells me that a Login #2 should've launched.
What is happening here is this: When SplashActivity
calls startActivity()
to launch LoginActivity
, the Intent
used contains FLAG_ACTIVITY_NEW_TASK
set (because SplashActivity
is declared with launchMode="singleInstance"
so it has to launch other activities into a new task), so Android looks for an existing task that has LoginActivity
as its root Activity
. If it didn't find one, it would simply launch a new instance of LoginActivity
into a new task. However, in this case, it finds one (this is task #2 in your diagram), so instead, it just brings that task to the foreground without launching a new instance of LoginActivity
.
This is the same behaviour as what happens when you have an app running, then press the HOME button and then click the app icon for that app again. Android doesn't launch a new instance of the app's root Activity
in this case, it simply looks for an existing task that has the app's launch Activity
as its root Activity
and brings that task to the foreground in whatever state it was in.
My suggestion for you is as follows:
singleInstance
and singleTask
BridgeActivity
which is used as a bridge between the web browser and your app. This Activity
should have the <intent-filter>
for the browser Intent
.BridgeActivity
should check if it is the root Activity
in its task. If it is not, it means that it has been launched into an existing task that was brought to the foreground and it can just quietly finish()
in onCreate()
.BridgeActivity
detects that it is the root of its task, it can launch SplashActivity
(make sure to set FLAG_ACTIVITY_NEW_TASK
) to begin a new task (since there obviously wasn't already an existing task of your app)BridgeActivity
should be declared so that it doesn't end up in the task stack history or in the list of recent tasks (noHistory="true"
and excludeFromRecents="true"
)