Mark
Mark

Reputation: 7718

How to get combined behaviour of FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_CLEAR_TASK?

There are so many questions on SO related to this, but no such direct questions I could find.

My app has a main activity M, and a sub activity S.

M launchMode is singleTask because I only ever want one instance running and I want S to exist in the same task as M.

S launchMode is standard, because it can have many instances.

In S, there is an Up button which must always take the user to M.

There are two types of task stack (with S on top):

  1. MSSSS...S

If the user presses Up in S, then the stack should become:

M (where M should be in the same state the user left it)

  1. SSSS...S

If the user presses Up in S, then the stack should become:

M (a new instance)

--

So how to construct the Intent for the Up button...

In the first case, FLAG_ACTIVITY_CLEAR_TOP should do the trick, but if we apply this to the second case then the user is dumped back in Home.

In the second case, FLAG_ACTIVITY_CLEAR_TASK will do the trick, but if we apply this to the first case, we discover that M is finished and restarted.

One might also be tempted to try FLAG_ACTIVITY_NEW_TASK, but then we find hitting Back from M will take the user to the screen where he/she hit Up.

Side note: how is this possible when M is singleTask and the activities all have the same (default) task affinity?

So how to correctly construct the Up Intent in this case?

Upvotes: 0

Views: 799

Answers (2)

David Wasser
David Wasser

Reputation: 95618

You cannot construct an UP Intent that will do what you want. Those things are mutually exclusive. What you could do is the following:

Change launch mode of M to singleTop

In M.onCreate(), check if M is at the root of the task by using isTaskRoot(). If it isn't the task root, have M restart itself and clear the task as follows:

Intent relaunch = new Intent(this, M.class);
relauch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(relaunch);

In your UP Intent, add the following flags: Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP.

This will ensure that if an instance of M already exists in the task, it will clear everything on top of that instance and call onNewIntent() on the existing instance.

If there isn't an existing instance of M in the task, it will launch a new instance on top of the stack. This instance will recognize that it isn't the root activity and it will clear the task and relaunch itself.

Note: This will only work on Android 3.0 and above (API 11 or higher).

Upvotes: 1

Mark
Mark

Reputation: 7718

Here is a workaround/hack using a (Lollipop) deprecated API:

ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
if (M_CLASS_NAME.equals(am.getRunningTasks(1).get(0).baseActivity.getClassName()) {
    // we should be able to just clear top - because M is already running
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
}
else {
    // okay to assume M is not running (because it is always root of task)
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
}

Upvotes: 0

Related Questions