I have a Notification which starts an Activity. After a long press on home button and selecting my app, I want to start my main Activity again, and not this Activity started by the Notification. I tried with FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, but this removed my whole application from the recents, and that's not what I want to achieve. How can I have my app in the recents, but have the main Activity started?
Regards
Okay, I found the solution to my problem. I started an Activity from a Notification with FLAG_ACTIVITY_NEW_TASK. But it seems to me that this Activity only gets started in an own task if affinity is different from the default affinity. So I had to add a different affinity in the manifest.
And it seems that FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS does not (as documented) exlucde the Activity from the recents, rather it excludes the whole task (not the whole application) in which the Activity gets started from the recents. And as I hadn't set a different affinity the Activity which I wanted to exclude was started in the same task (although I had set FLAG_ACTIVITY_NEW_TASK) and so my whole application (as it was running in only one task) was excluded from the recents.
Now I've set a different affinity for the Activity that gets started from the Notification and I start it with FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. When I leave this Activity and long-press the HOME button I can choose my app and the default task is started or brought to the front.
If it's wrong what I mentioned above, feel free to clear it up ...
It's not clear to me what you want.
"How can I have my app in the recents, but have the main Activity
started?"
If you want to always start one activity using the long home-press, you can define your activity as singleTask in the manifest.
That way, when you select the shortcut in the long press HOME, it will always show the MAIN, singleTask activity. I say this because I used this behavior before once. ;-)
I believe that by using this you can still start an activity from the notification normally, using, say, Intents.
In the activity tag:
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Related
This question already has answers here:
Android: bug in launchMode="singleTask"? -> activity stack not preserved
(12 answers)
Closed 2 years ago.
My launcher activity has the launchMode attribute set to singleTask due to certain requirements.
<activity
android:name=".map.MapsActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="#style/MapScreenTheme"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The problem I'm facing is that if I open another activity -> press home -> Click on app icon in launcher application -> It opens the MapActivity and not the activity that was previously open.
This however does not happen if I navigate to the app via the recents menu. Then the newly opened activity stays on top.
Can someone please explain what is happening here with regards to the backstack and why is the ActivityManagerService not taking into account that the app process already exists and yet decides to start the launcher app and clear the backstack and not simply bring the app forward?
This issue can be observed in a small sample app created here -
https://github.com/abhiank/SingleTaskActivity
I think this is the desired behavior of SingleTask launch mode. Keeping Launcher Activity as SingleTask has its consequences.
I can not think of an exact solution for this problem but some workaround will do the Job.
Adding the link below which i have mentioned in comment to go through.
Android: bug in launchMode="singleTask"? -> activity stack not preserved
I think, When you click on app icon again, It opens the Launcher Activity on top of your previously opened Activity. What you can do is apply a simple check whether there are any activity in the backstack apart from this, then finish this launcher activity, It will reveal previously opened screen. Try the below link.
https://stackoverflow.com/a/38450232/3497972
check these links too, they have other ways to maintain screen when launched app icon, when app is in background
How to make an android app return to the last open activity when relaunched?
Android app restarts when opened by clicking app icon
Determine when application icon is clicked to launch the app in android
What is the difference between launch app from "recent apps" and tapping app icon
There is some solution for case when your main activity would be launched only by other activities within your own application:
You can remove launchMode attribute from your main activity definition in manifest. And just pass Intent.FLAG_ACTIVITY_NEW_TASK to every intent that opens your MainActivity, for example like this:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Be aware that behaviour of Intent.FLAG_ACTIVITY_NEW_TASK or launchMode="singleTask" within your own application only works in conjunction with taskAffinity attribute on activity definition in manifest.
I hope it will help you a little.
Sounds to me like you are seeing this nasty long-standing Android bug
Re-launch of Activity on Home button, but...only the first time
To test whether that is the case, please kill your app (settings->apps->your app->force quit). Then launch your app by tapping the app icon on the HOME screen. Do whatever you need to do to launch another Activity into the task. Press HOME. Now tap the icon on the HOME screen again. This should bring your task to the foreground in the same state you left it in.
After looking into the codes i need to maintain/modify and the different documents and explanation, i really got confused single task and task affinity.
https://developer.android.com/guide/topics/manifest/activity-element.html
https://www.slideshare.net/RanNachmany/manipulating-android-tasks-and-back-stack
https://developer.android.com/guide/components/activities/tasks-and-back-stack.html
What i understand is activity launch mode singleTask will create a new task and put that activity at the root of the task. "singleTask" and "singleInstance", should be used only when the activity has an ACTION_MAIN and a CATEGORY_LAUNCHER filter
activity taskAffinity is the task that the activity has an affinity for. By default all the activities share the same affinity, the default package name. If want to have the activity different affinity task, then define another name and launch with FLAG_NEW_ACTIVITY_TASK.
In my maintain code(not the original developer), there have so many activities in AndroidManifest.xml with launchMode singleTask.
<activity name="LauncherActivity"
launchMode="singleTask">
<intent-filter>
<action name="action.MAIN" />
<category name="category.LAUNCHER />
</intent-filter>
</activity>
<activity name="TabsActivity"
launchMode="singleTask">
</activity>
<activity name="SubTab1"
launchMode="singleTask">
</activity>
<activity name="SubTab2"
launchMode="singleTask">
</activity>
<activity name="SubTab3"
launchMode="singleTask">
</activity>
<activity name="SubTab4"
launchMode="singleTask">
</activity>
<activity name="ScreenActivity"
launchMode="singleTask"
taskAffinity="com.xxx.xxx.sa"
excludeFromRecents="true">
</activity>
When click on user icon,
it will launch the LauncherActivity. LauncherActivity do some tasks for checking and launch TabsActivity and finish
itself(LauncherActivity).
TabsActivity add Tabs (SubTab1, SubTab2, SubTab3, SubTab4).
ScreenActivity will be launched startActivity with
FLAG_ACTIVITY_NEW_TASK.
ScreenActivity also put a notification icon so that the user can directly back to this activity.
SubTab can launch the other standard launchMode which will be destroyed after use back key.
EveryTime user click on App icon, it will take to TabsActivity instead of the last activity the user interact. So I add some code in the LauncherActivity onCreate()
if (!isTaskRoot() && !TextUtils.isEmpty(action)) {
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) &&
Intent.ACTION_MAIN.equals(action)) {
finish();
return;
}
}
This successfully bring to the last activity that the user interact.
The first question comes to me that isTaskRoot(). According to the explanation:
boolean isTaskRoot ()
Return whether this activity is the root of a task. The root is the first activity in a task.
LauncherActivity defined as singleTask as mentioned above, so it should be the root in the task. But when onCreate() check that, it is not the root task when there is other activity is launched including SingleTask activity. When TabsActivity is launched, when click on AppIcon, LauncherActivity onCreate() isTaskRoot() return false.
LauncherActivity and TabsActivity, they should be in different tasks and in each task, each would be the root activity.
In some other comments, it mentioned that isTaskRoot() is true when there are no activities in activity stack. So if there is activity in the stack, if will return false. So it is more related to the stack instead of task? I really get confused. Can someone explain about why it is different with document explanation.
The second modification is that I removed the ScreenActivity taskAffinity. In the old design, ScreenActivity can be be backed to through clicking on notification. But there is new request that if there is ScreenActivity last launched by user, when click on App icon, it should back to that activity. After removed taskAffinity in AndroidManifest, it does happen what i want.
I am looking this slide share tutorial. But still not get that.
https://www.slideshare.net/rajdeep/managing-activity-backstack
My question is that if the singleTask without taskAffinity, how they create a new task for each different singleTask activity. How the backstack works?
After modification, LauncherActivity, TabsActivity, ScreenActivity are SingleTask with the same default package name task. So they are in the same task stacked? If yes, it is not the same with document explanation. Please help me to get more clear of that.
Thanks a lot.
I have the problem that my App is starting again if the user clicks the launcher icon even if it is already running. I used singleTaks for that Activity and as many Stackoverflow Answers said -> This should solve the problem - but it doesnt.
<activity
android:name=".activities.ActivitySplash"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
As you can see i did define the launchMode to be singleTask. I open the App. Navigate to Screen X (I even could stay on the Startscreen, has the same effect) and now i press the home button. When i now press the launcher icon again the already running app does not pop up or is getting resumed (call it as you wish). Instead the App is completly started new.
How can i prevent that behaviour, if singleTask isnt working?
Try with SingleTop:
if the target task already has an existing instance of the activity
at the top of its stack, that instance will receive the new intent (in
an onNewIntent() call); a new instance is not created. 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.
Our application has a splash activity (main activity for launcher) and many other activities. In most cases, when the user switches the application into background and resumes it from launcher, the old activity stack is resumed and top activity in that stack is shown as expected.
However, when the apk is just installed on the phone, or a new apk (with higher version) of the same application is installed, its behavior is strange. When the application is switched to background and resumed from launcher, the previous activity stack is not resumed and the splash activity is always shown. If we resume the application from recent applications list, the activity stack is resumed as expected. Only after killing the task from recent applications list, everything becomes normal again. The previous activity stack will always be resumed correctly until it is replaced by another apk installation again.
My Android version is 4.1.2 and I am using its default launcher.
Following is configuration of the splash activity.
<activity android:name=".welcome.activity.SplashActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Who has any idea about the strange behavior? Thanks in advance!
Finally I have found this is an issue of Android system. It has already been discussed in Activity history stack wrong upon first install on device?.
I have adopted a workaround stated in https://code.google.com/p/android/issues/detail?id=2373#c40 and it works well, i.e. adding the following code in SplashActivity.onCreate():
if (!isTaskRoot()) {
Intent intent = getIntent();
String action = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
I'm not really able to tell what's going on without knowing more about your app. I would look into:
The launchMode manifest element: android:launchMode
Check your activities are not being destroyed and recreated by the system: Recreating an Activity
If you are doing anything with fragments and if these are maintaining state correctly
Sorry, bit of a guess!
Since you only want to show your Splash Activity once, you can use finish() after you launched the Main Activity, that should solve your problem.
In my application, I have specified a second activity that can be launched from the launcher, using this manifest entry:
<activity
android:name=".Lists.ListOfListsActivity"
android:icon="#drawable/ic_launcher_lists"
android:launchMode="singleTop"
android:label="#string/lists_activity_name" >
<!-- An Intent filter so that the Lists activity shows in the Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Let's say I have the app open at the "main" activity then press the home key. My app will still be running, but in background.
Later the user selects the launcher icon I have for "ListsOfListsActivity" from the homescreen.
This will bring the application to the foreground, but NOT at the "ListOfListsActivity", but at whatever it's current activity was when it went to the background (e.g. at the "main"activity).
This is confusing, as the user selected the "ListOfListsActivity" but is shown another one. Then they have to navigate to it.
I had this working better, by specifying launchMode = "singleTask" for the "ListOfListsActivity", but in that mode it cannot be launched from another activity for a result (startActivityForResult() ), and I need to be able to do that to pick a list...
Question:
- how to specify an intent-filter that will force an activity to the foreground and be the selected activity, no matter what the current status of the application and it's current activity??
My final implementation was to define a different taskAfinity string for each activity I wanted to launch independently from the Launcher.
That way, each "shortcut" always launches the activity I want, but the downside that I have not been able to avoid is that the user may have multiple tasks with an activity from my application in it, and maybe the same activity open/active in different tasks....