8

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

vepzfe
  • 4,217
  • 5
  • 26
  • 46
  • 2
    Have you tried Any solution from [This thread](https://stackoverflow.com/questions/2417468/android-bug-in-launchmode-singletask-activity-stack-not-preserved)..? – ADM Apr 17 '20 at 10:52
  • @ADM. Thank you so much. I cannot believe I did not find this thread despite all the searching. So, ultimately the solution is to have a helper activity which starts the main activity since singleTask simply kills all other activities above it. – vepzfe Apr 17 '20 at 11:05
  • Yeah it got me thinking that this is an obvious issue it should had been asked before. So I digged a bit. If you got a solution then add an answer and accept it to close the Bounty. – ADM Apr 17 '20 at 11:10
  • 1
    Yup. I guess I should've dug deeper. Well, that is not really a solution. Just a hacky workaround. I think best would be we mark this thread as duplicate and reference that thread. – vepzfe Apr 17 '20 at 11:19
  • Generally speaking, using a special `launchMode` causes more problems than it solves. Please explain why you think you need this special launch mode. – David Wasser Apr 18 '20 at 11:10
  • @DavidWasser I need this so that multiple instances of this activity do not open. In this activity I show a map with a route. In parallel I have a feature where a user can share a google maps link to the app. To parse the location and place name from that link I open a new activity on a different task (so that it does not get stacked on top on the map activity task). If the parsing succeeds then I open the map activity. If I do not mention singleTask, then two instances of the map activity - one in the original one and one on the google maps link one will open with the same loaded route. – vepzfe Apr 18 '20 at 17:31
  • You should be able to solve this problem using `taskAffinity` and you won't need special launch modes. – David Wasser Apr 18 '20 at 19:10
  • @DavidWasser I am making use of `taskAffinity`. Thats how the url sharing activity is not effecting the main back stack. I would have loved to use taskAffinity on the main backstack as well, but the problem with that is that I cannot set a custom taskAffinity in the intent to open the main activity from the url activity. – vepzfe Apr 18 '20 at 19:46
  • @ADM, can you please submit the link that you shared as an answer. I'll give the bounty to you. I'm unable to mark this question as duplicate until there is an open bounty. – vepzfe Apr 18 '20 at 19:47
  • please post your manifest. I don;t think this is correct and would like to reproduce the behaviour myself. – David Wasser Apr 19 '20 at 14:58
  • Also, I just found a very detailed answer of mine to a related question, albeit not the behaviour of `launchMode="singleTask"`. Have a look at this: https://stackoverflow.com/a/29376250/769265 The use of "task reparenting" might be a way for you to solve your problem. – David Wasser Apr 19 '20 at 15:19
  • @DavidWasser I've created a small repo to demonstrate this issue here - https://github.com/abhiank/SingleTaskActivity – vepzfe Apr 19 '20 at 15:49
  • @DavidWasser Thanks for the link to your answer on task reparenting. I'd never heard or used it before. It might solve my usecase by removing singleTask itself (although I'm not yet sure), however it wouldn't solve this current issue since both the activities are in the same task with same task affinity. Also, thanks for your explanation about diff between launch from app icon vs recents. Would be great it if you could expand on that. That is something that is still perplexing me. I was thinking of digging into the source code myself too. – vepzfe Apr 19 '20 at 16:29

4 Answers4

3

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

ADM
  • 20,406
  • 11
  • 52
  • 83
  • This is not correct. The desired behaviour of `singleTask` is described here: https://developer.android.com/guide/components/activities/tasks-and-back-stack#ManifestForTasks If you look at "Figure 4" it even explicitly shows a task containing 2 activities where the root `Activity` is declared with `launchMode="singleTask"` – David Wasser Apr 19 '20 at 15:06
  • Thx @DavidWasser i'll take a read .. – ADM Apr 19 '20 at 15:10
  • 1
    Actually, I just found a very detailed answer of mine to a related question that covers a lot of this topic (albeit not specifically the behavour of `launchMode="singleTask"`. Have a look here: https://stackoverflow.com/a/29376250/769265 – David Wasser Apr 19 '20 at 15:17
2

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

akashzincle
  • 1,108
  • 6
  • 15
  • Thanks for your answer. I tried the answer that the question in your link mentioned. However, onCreate is never called since the activity with "singleTask" if its in the backstack. I tried putting that same code in the onNewIntent() and it was called, however, by that time isTaskRoot() was already true. Meaning that the backstack was already cleared and this activity was already put on top before onNewIntent was called. Thanks again for the link though. That question too had the same problem as I'm facing. – vepzfe Apr 17 '20 at 06:24
  • @abhiank updated answer with more links, which has other approaches also, might help u, go thorugh them – akashzincle Apr 17 '20 at 21:44
  • Thanks again for those links. Interesting reads. However, none of them were useful. Most of them were about issues with regards to app opened from installer "open" button vs launcher icon click. I was hoping your last link will have some in-depth working on what happens differently when app is resumed from recents but alas, it did not have the needed info. – vepzfe Apr 18 '20 at 18:05
0

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.

  • Thanks for your answer. This does not work for me though. I cannot control the intent the launcher activity. That is controlled by the launcher app and the activity manager service. Also, I don't have a need to open the activity in a new task. I'm okay with the main activity opening in the default task. I only want to understand why is launcher activity with single task always pushed to top of backstack. – vepzfe Apr 12 '20 at 08:15
  • Intent.FLAG_ACTIVITY_NEW_TASK and launchMode="singleTask" has identical behaviour. The essence of my suggestion is to set "singleTask" mode through intent flag, instead of attribute. Of course, if your app will be used by other apps (send intents to it), my solution will not work for you, otherwise you will have full control of intents to your main activity. What about intent from launcher app, there is no need to control it, with this approach it works well. – Николай Гольцев Apr 12 '20 at 09:49
  • I understand. However, the problem is that I do not control the intent that opens the launcher activity. The launcher activity is simply opened by the activity manager service. – vepzfe Apr 17 '20 at 06:28
  • I mean that if your main activity serves as helper for another apps. Assume situation: user wants to send email from some app, when he does so, Android system maintains this action and the result of this will be some activity (from current app or another app, it doesn't matter, just activity that can perform this task) with which user can complete his send email task. Now, if your main activity is not "some activity" described above, my solution works well, otherwise of course you should get another solution. – Николай Гольцев Apr 17 '20 at 07:53
  • Are you saying I use a common activity which is the launcher activity and use that to start my main activity? – vepzfe Apr 17 '20 at 11:02
  • I'm trying to say, that if your launcher activity will be started ONLY by your app's other activities OR from home screen, then you could use my solution and it works well for this case. – Николай Гольцев Apr 17 '20 at 11:15
  • I'm sorry but I still dont understand how exactly would I set flag = Intent.FLAG_ACTIVITY_NEW_TASK if the activity is opened from home screen. That part is controlled by the ActivityManager and I cannot set a flag there! – vepzfe Apr 17 '20 at 11:24
  • Ok, I understood. You don't need handle this specific case (change intent from home screen), it works well if you just leave it as is. – Николай Гольцев Apr 17 '20 at 11:29
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211866/discussion-between---and-abhiank). – Николай Гольцев Apr 17 '20 at 11:30
  • Your solution still does not work. I clearly mentioned in the question the problem is HOME -> A -> B -> HOME then press on app icon is opening A and not A->B. I never mentioned that A is being opened from any other activity. – vepzfe Apr 17 '20 at 11:31
0

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.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Hey @David, thanks for your answer. However, this is not the bug I'm facing. The bug in fact is this one - https://stackoverflow.com/questions/2417468/android-bug-in-launchmode-singletask-activity-stack-not-preserved – vepzfe Apr 18 '20 at 17:13
  • The linked question describes basically the same bug. There are answers to that question that are just plain wrong, but if there is a bug it is the bug that I've described. Have you tested this by doing what I suggested? – David Wasser Apr 18 '20 at 19:14
  • I did try it. This is not the scenario which is happening. These are separate bugs. In my case, onCreate is not called for the main activity. First onDestroy is called for Activity B, then onDetachedFromWindow and finally onNewIntent for the mainActivity. And in newIntent, isTaskRoot() is always true. Actually at this point I don't think this can be called a bug. Seems like activity with singleTask behave this way. The only solution is having a delegate activity. – vepzfe Apr 18 '20 at 19:42