0

I'm trying to understand the Android Tasks and Back stack by reading the official documentation: https://developer.android.com/guide/components/activities/tasks-and-back-stack

I have a couple of questions regarding the documentation.

Question 1: In Figure 4. in the documentation, there are 2 tasks - a foreground and a background task, the background tasks contains Activity Y and X, if the Activity Y is declared with a singleTask launch mode, how is it possible to create a task with activity Y on top of activity X?

For other questions, I prepared a simple project - 2 activities, A and B. On both activities I have 2 buttons:

  • Button A opens Activity A
  • Button B opens Activity B

Activity A is the MAIN (LAUNCHER) activity.

Question 2: The documentation says that using the intent flag FLAG_ACTIVITY_NEW_TASK produces the same behavior as using the singleTask launcher mode:

This produces the same behavior as the "singleTask" launchMode value, discussed in the previous section.

This is not what I see from my test application. If the activity B has a launcher mode set to singleTask and if my backstack is A -> B -> A -> A, then if I open B the back stack will look like A -> B (it will pop the last 2 As). I guess that the reason behind it is the tasks created: when the launcher intent was sent it opened the activity A in the new task (let's call it to task 1), when I opened B, it opened it in task 2 (because it has a singleTask launch mode), then the 2 A activities where opened in Task 2 as well. After opening B again, Android found a task that already has a B activity (Task 2) and it brought it to the front, poping 2 As.

However, using a FLAG_ACTIVITY_NEW_TASK instead of singleTask does not produce the same behavior, it just opens B on top of everything else. Is the documentation wrong, or am I doing something wrong?

Question 3: The example at the end says:

the two launch modes that mark activities as always initiating a task, "singleTask" and "singleInstance", should be used only when the activity has an ACTION_MAIN and a CATEGORY_LAUNCHER filter. Imagine, for example, what could happen if the filter is missing: An intent launches a "singleTask" activity, initiating a new task, and the user spends some time working in that task. The user then presses the Home button. The task is now sent to the background and is not visible. Now the user has no way to return to the task, because it is not represented in the app launcher.

How to reproduce that? In my previous example, I open the activity B in a new task, but if I hit the home button and the launcher icon again, I get back to activity B. So even though I'm using a singleTask launcher mode, I'm still able to return to that task by using the launcher icon or selecting it from the list of the recent applications.

It's entirely possible that I'm doing something wrong here and that new tasks are not generated, is there a way to see all tasks and activities for a specific application?

Thanks.

Markotron
  • 50
  • 8
  • In general, I was wrong about creating tasks. No new tasks were created in my example. And that's because the `taskAffinity` property wasn't set. Which means that Android will search for a task that has a default app package name. The answer to question 2: https://stackoverflow.com/questions/46427805/why-behaviours-are-different-androidlaunchmode-singletask-androidtaskaf – Markotron Mar 20 '19 at 17:15
  • I guess that the answer to question 3 is to use the android version lower that Lollipop. – Markotron Mar 20 '19 at 17:28

1 Answers1

0

Today I spent more time trying to understand what's going on here and I think I have the answers. I realized that nothing in my example created new tasks. Tasks are visible in the Recent screens (apps in the background) - at least on Android 5+.

So, the first question that should be answered is: Why creating activity B is not creating a new task?

It's because generating new tasks goes hand in hand with the taskAffinity property. If you don't specify this property, your activity will have the default taskAffinity which is your application's package name. When you open the activity with a singleTask launcher mode, Android will look for tasks with the same affinity (task's affinity is defined by its root activity affinity) and if it finds one it will add your activity to that task. Because I didn't specify the affinity, android assumed I want to add my activity to the task with an affinity equal to the application's package and it didn't create new tasks at all. It just added an activity to an existing task.

That being said, FLAG_ACTIVITY_NEW_TASK and singleTask are very much different, although sometimes they produce the same behavior. If you trigger an intent with the FLAG_ACTIVITY_NEW_TASK flag that is trying to open an activity A without specifying activity's taskAffinity you'll just normally add an activity on top of the current task. (This is still confusing to me, I would expect it to open an activity only if the activity is not in the stack; if it is, it should do nothing.)

Opening the same activity without this flag but using the singleTask mode, will again not create a new task but will:

  1. Add the activity on top if it's not in the stack (this is the answer to question 1)
  2. Destroy all activities on top of yours and call onNewIntent if the activity is already in the stack. (I think that branch.io uses this method to handle deep links - which seems really hacky to me, but...)

On the other hand, if you specify the taskAffinity for your activity then:

  • if singleTask mode is set, android will search for the task with this affinity and if it's present it will

    1. add your activity on top if the activity is not on task's backstack
    2. destroy all activities on top of your activity and call onNewIntent if the activity is in the back stack.

If the task is not present, it will create a new one and add your activity as root.

  • if FLAG_ACTIVITY_NEW_TASK flag is set in the intent, android will search for the task with the specified affinity and if it finds one it will just bring that task to the foreground, without destroying the stack or calling onNewIntent. (I tested that if the activity is in the back stack, I guess that if the activity is not in the back stack it would push it to the task's stack).

So, to answer question 2. The flag FLAG_ACTIVITY_NEW_TASK and the launcher mode singleTask are different. I guess that similar behavior can be achieved by using 2 more flags FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP.

I think that the example in the documentation regarding question 3 is relevant for older versions of Android (lower than 5.0). There different tasks were not shown in the Recent Screens - here's the documentation: https://developer.android.com/guide/components/activities/recents.

Markotron
  • 50
  • 8