androidandroid-intentandroid-launcherback-stacklaunchmode

Understanding Android Launch modes with splash screens


I have 3 activities: Splash (launcher), Login, Dashboard. When app is opened Splash waits some time and then starts Login, finishing 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) standard mode

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: single taask

Lastly If I choose singleInstance, the following happens:

single instance 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>

Solution

  • 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: