android singleTask activity not as the root?
Asked Answered
M

1

7

I've been reading doc regarding to launch modes and there is one thing I don't understard. The doc says that singleTask activity is always the root of the stack:

In contrast, "singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task.

But: if you look at this part of doc at Figure 4, you see that when Activity 2 starts Activity Y (puts that task to foreground), Activity Y was already on the top of the task and will be on the top of the current task, not the root.

I tried this scenario in this simulation app and when I create singleTask activity, it always creates a new task. However, if the only instance already exists, it finishes all activities above this one so the only instance can be the root (and also the only activity in the task).

How could the Activity Y become on the top of the task above the Activity X?

Is there any other reason I'm missing?

PS: I also don't really understand the difference between Task and back stack.

Mammalian answered 26/11, 2015 at 16:46 Comment(0)
P
13

As usual (sigh), the documentation is wrong. In the diagram you referenced, obviously Activity Y can't be defined as singleTask and yet be the top activity in a background task containing 2 activities.

When testing scenarios with special launch modes singleTask and singleInstance, please be aware that taskAffinity plays an important role in this behaviour, as taskAffinity takes priority over special launch modes.


Regarding the difference between "task" and "back stack":

A "task" is a stack of activities that can be manipulated as a whole group.

  • When you launch an application (assuming that it isn't currently running), Android creates a new task which is in the foreground and contains the root activity of the application you launched.
  • When that activity starts new activities, these new activities are added to current task (usually, although there are exceptions to this behaviour).
  • When you press the HOME button, the current task is moved from the foreground to the background.
  • When you show the list of "recents", what is displayed is the list of recent tasks, not the list of recent activities or list of recent applications.
  • When you select a task from the list of recent tasks, if that task is still active (still has live activities in it), the entire task (including all of its activities) will be brought from the background to the foreground.
  • Tasks can also be "stacked". When an activity in the current task starts an activity in a new task, the new task is stacked on top of the current task. This only serves to control what happens when the new task completes. In the usual case, when the new task completes (all of its activities have finished), Android will return the user to the previous task (ie: the task that started the completing task).

A "back stack" usually refers to a set of activities within a task. Each task has its own stack of activities. This is used to control what happens when the current activity (the one on top of the back stack) finishes. Normally Android returns the user to the activity that is directly underneath (below) the finishing activity in the back stack.

The Android code and documentation often refer to the "root" of a task (this is the activity that was used to start the task) and the "top" or "front" of a task (this is the activity that is currently being shown).


Actually, the documentation lies :-( Here's an example:

In contrast, "singleTask" and "singleInstance" activities can only begin a task.

This statement is usually, but not always correct. For example, let's say I have 2 activities: A and B. A is the launch activity (ie: the one with ACTION=MAIN and CATEGORY=DEFAULT) and is defined with standard launch mode. B is defined with launchMode="singleTask". I start the application and Android creates an instance of A. In A I then do:

startActivity(new Intent(this, B.class));

This will create a new instance of activity B and put it on top of A in the same task. It will not create a new task with activity B as the root. The reason is that activity A and activity B have the same taskAffinity (by default all activities of an application have the same taskAffinity), and Android will ignore the launch mode of B in this case.

The documentation also says:

Moreover, the device can hold only one instance of the activity at a time — only one such task.

Again, taskAffinity can break this behaviour. Assume again we have A, B and C, all with the same (default) taskAffinity. A and C have standard launch mode, B has launchMode="singleTask". If A starts B, the instance of B ends up not in a new task, but in the same task as A (see above). Now B starts C. Android creates an instance of C and puts it on top of B in the same task. Now C calls:

startActivity(new Intent(this, B.class));

Android creates a new instance of B and puts this on top of C in the task. There are now 2 instances of B and neither of them is the root activity of the task! This behaviour is also due to the fact that taskAffinity trumps launch mode.

Pika answered 26/11, 2015 at 17:30 Comment(5)
Thanks for the difference! But the affinity you described still keeps me wondering. If I try your first example in the app I've specified in my original post, it behaves as expected - new task is created. To correspond to what you've said... they had to change the affinity to get that behaviour? I've doubts about that.Mammalian
You're right. I've created a sample project and it works as you said. They really had to change the affinity I guess. Or just different package name is enough? (I usually have all activities in the same package) But how can I accomplish this behaviour in my app when I want to open new task? I must specify different affinity in every activity? That's weird.Mammalian
Task affinity is used to group activites together that should be in the same task. In general, in a single application, you will want all (or most) activities in the same task. It is rare that you need to create multiple tasks. If you really need to create multiple tasks there are lots of "gotchas", because you also need to make sure that the user can tell the difference between the tasks so that he can return to the correct one. This usually means having different application icons and different application names for the different tasks. Please describe why you need different tasks.Pika
I am not sure. I have a login activity (A) that is finished after successful login. Then is B -> C where e.g. an exception is thrown. Now I want to discard both B and C and show A in a different task so the user can not navigate back... Is this the scenario where taskAffinity can take place? I've read that I can achieve this just by using intents with appropriate flags.Mammalian
I cannot reproduce the case with two (or more) instances of the same Activity with launchMode="singleTask" in the same task. Starting a new instance already having one in a stack just opens the existing Activity while clearing the stack's top. Task affinity is the same for all activities.Danedanegeld

© 2022 - 2024 — McMap. All rights reserved.