Issue
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)

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>
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:
- Get rid of the use of the special launch modes
singleInstanceandsingleTask - Create a new
BridgeActivitywhich is used as a bridge between the web browser and your app. ThisActivityshould have the<intent-filter>for the browserIntent. - The
BridgeActivityshould check if it is the rootActivityin 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 quietlyfinish()inonCreate(). - If
BridgeActivitydetects that it is the root of its task, it can launchSplashActivity(make sure to setFLAG_ACTIVITY_NEW_TASK) to begin a new task (since there obviously wasn't already an existing task of your app) BridgeActivityshould be declared so that it doesn't end up in the task stack history or in the list of recent tasks (noHistory="true"andexcludeFromRecents="true")
Answered By - David Wasser
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.