← Back to android roadmap

Android Launch Modes: Where Will My Activity Open?

One decision tree for standard, singleTop, singleTask and singleInstance, then the platform code that runs it: which task an Activity lands in, and whether you get a new instance or onNewIntent(). With the class map, edge cases and cross questions.

  • Android
  • Activities
  • Tasks & back stack
  • Launch modes
  • Internals
On this page
  1. What you’ll study
  2. The basics
  3. The high level
  4. Checkpoint
  5. The low level
  6. Why it helps
  7. The map
  8. Edge cases
  9. Cross questions
  10. Revision: key points
  11. The fine print

What you’ll study

  1. What a task and its back stack are, and what a launch mode changes.
  2. The two routes every launch takes: stay in the caller’s task, or find a task by affinity.
  3. The four outcomes: reuse, create, clear the top, new task.
  4. The four modes, and the intent flags that stand in for them.
  5. How the system decides, step by step, in ActivityStarter.
  6. The traps: affinity, results, non-Activity contexts, singleInstance and Back.

How it connects

A launch mode only answers two questions: which task, and new or reused. The first is decided by whether the launch ends up with FLAG_ACTIVITY_NEW_TASK; if it does, taskAffinity picks the task. The second depends on the mode and on what’s already in that task. Every edge case in this guide is one of those two answers coming out differently than you expected.

Read it at your level

Level Read You should be able to
Student The basics, the tree, the phone demo Say what a task is and what each mode does, in one line each
Fresher + the checklist and quick reference Predict the back stack after any launch in the demos
Junior + Why it helps, the first eight cross questions Fix duplicate screens and “wrong Back” bugs; answer the common interview questions
Mid + The low level, The map Explain where the decision is made and why singleTask can stay in your own task
Senior + Edge cases, the last five cross questions Reason about results, non-Activity contexts and affinity across apps; debug with dumpsys

The basics

Every screen you open goes into a task: a stack of Activities the user moves through with Back. Recents shows one card per task. Most of the time an app has one task, and every startActivity() pushes a new Activity on top of it.

Launch modes change that default. You set one on the Activity in the manifest (android:launchMode), or ask for similar behaviour per call with intent flags:

<activity
    android:name=".TargetActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.example.reader" />

Every startActivity(T) then answers two questions: which task does T open in, and does Android create a new T or reuse one and call onNewIntent()? Launch modes, taskAffinity and FLAG_ACTIVITY_NEW_TASK all feed into those two answers, which is why they are easy to mix up when you learn them one by one.

The high level

Seen as a single decision tree, they stop being four special cases. There are only two routes: stay in the caller’s task, or go looking for a task by affinity.

startActivity(T)
│
└─ Does the launch ask for a task search?
   (singleTask, singleInstance, or the intent has FLAG_ACTIVITY_NEW_TASK)
   │
   ├─ NO ─► T joins the caller's task
   │        └─ singleTop AND T already on top of the stack?
   │           ├─ YES ─► REUSE: deliver onNewIntent()
   │           └─ NO  ─► CREATE: push a new T on the caller's stack
   │
   └─ YES ─► Is there a task with T's taskAffinity?
             ├─ NO  ─► NEW TASK: create a task with T as its root
             └─ YES ─► bring that task to the front, then by launch mode:
                       │
                       ├─ singleInstance
                       │  └─► T lives alone: REUSE, deliver onNewIntent()
                       │
                       ├─ singleTask: is T already in this task?
                       │  ├─ YES ─► CLEAR TOP: destroy everything above T,
                       │  │         REUSE, deliver onNewIntent()
                       │  └─ NO  ─► CREATE: push a new T on this task
                       │
                       └─ standard / singleTop + FLAG_ACTIVITY_NEW_TASK
                          └─ singleTop AND T on top of this task?
                             ├─ YES ─► REUSE: deliver onNewIntent()
                             └─ NO  ─► CREATE: push a new T on this task

Every leaf ends in one of four outcomes: reuse the T you have, create a new T on an existing stack, clear the top of a task down to T, or start a new task with T as its root.

Interactive demo: pick a launch mode, set the intent flag and the state of the back stack, and watch the path through the tree and the tasks before and after. Needs JavaScript.

Watch the base cases on a phone

The same rules, played on a device. Each card is one Activity instance with its own number, so you can see when Android reuses the one you have and when it makes another. Press Back after a launch: where you land is the part people usually get wrong, especially with singleInstance.

Interactive demo: a phone that plays each base case (standard, singleTop on and off the top, singleTask, singleInstance, and FLAG_ACTIVITY_NEW_TASK with its own affinity) as you launch T or press Back. Needs JavaScript.

The checklist to run in your head

Whenever you see a launch, run these three steps.

  • No: standard or singleTop without the flag. Go to step 2: it stays in the caller’s task.
  • Yes: singleTask, singleInstance, or FLAG_ACTIVITY_NEW_TASK on the intent. Go to step 3: now taskAffinity decides.

Step 2: The caller’s task (standard and singleTop)

T stays in the same task as the screen that called it. Ask one thing: is it singleTop and already at the very top of the stack?

  • Yes: don’t create a new one. Call onNewIntent().
  • No (it’s not on top, or it’s standard): push a brand-new instance on top of the stack.

Step 3: Affinity and task (singleTask and singleInstance)

  1. Find the matching task. Does a task with this Activity’s taskAffinity exist?
    • No: create a new task with that affinity and create the Activity inside it.
    • Yes: bring that task to the foreground.
  2. Look inside that task.
    • singleTask: does the Activity already exist in that task?
      • Yes: pop and destroy every Activity above it so it reaches the top, then call onNewIntent().
      • No: create a new instance and place it on top of that task.
    • singleInstance: the Activity is already alone in its own task. Call onNewIntent().

Quick reference

Launch mode Looks for a task? Reuses an instance when Others in its task?
standard Only with the flag Never Yes
singleTop Only with the flag It’s on top of the stack Yes
singleTask Always It’s anywhere in the task (clears above it) Yes
singleInstance Always It exists at all No, it’s alone

Checkpoint

Before going deeper, you should be able to say:

  • A launch either stays in the caller’s task or searches for a task by taskAffinity.
  • singleTask, singleInstance and FLAG_ACTIVITY_NEW_TASK cause the search; standard and singleTop don’t.
  • Reuse means onNewIntent(), not onCreate().
  • singleTop only looks at the top; singleTask looks through the whole task and clears above T.

If any of these is fuzzy, play the two demos again before reading the code.

The low level

The tree above is a model. The real decision is made in the system server, in ActivityStarter (package com.android.server.wm, AOSP frameworks/base). Following one launch through it, these are the steps that map onto the tree:

1. Read the launch mode, and force a new task where required

setInitialState() reads the target’s launchMode from its ActivityInfo. In code the modes are numbers: LAUNCH_MULTIPLE (0, which is standard), LAUNCH_SINGLE_TOP (1), LAUNCH_SINGLE_TASK (2), LAUNCH_SINGLE_INSTANCE (3) and LAUNCH_SINGLE_INSTANCE_PER_TASK (4).

It adds FLAG_ACTIVITY_NEW_TASK straight away for singleInstancePerTask, and for an Activity whose required display category differs from the caller’s. Then, if the intent asks for a new task and a result, it cancels the result on the spot (more in the edge cases).

2. Decide whether to search for a task: computeLaunchingTaskFlags()

This is step 1 of the checklist, in code. FLAG_ACTIVITY_NEW_TASK is added when:

  • there is no calling Activity (a Service, a receiver, the application Context); the log says “startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK”;
  • the caller is singleInstance, because nothing may join its task;
  • the target is singleTask or singleInstance.

So “does it ask for a task search?” really means “does the launch end up with NEW_TASK?”

3. Find a task to reuse: resolveReusableTask()

Android only tries an existing task when the launch has NEW_TASK (without FLAG_ACTIVITY_MULTIPLE_TASK) or the target is singleTask/singleInstance, and the caller is not waiting for a result. Then:

  • singleInstance searches for the Activity itself (findActivity): “there can be one and only one instance … always in its own unique task”, as the source puts it.
  • Everything else asks RootWindowContainer.findTask() for the best task, matched by taskAffinity.
  • singleInstancePerTask only reuses a task whose root is that Activity, even if another task has the same affinity.

4. Reuse instead of create

  • Top of the stack (singleTop). deliverToCurrentTopIfNeeded() skips creating T when the top running Activity is the same component, for the same user, still attached to a process, and the launch is singleTop or has FLAG_ACTIVITY_SINGLE_TOP.
  • Clear the top (singleTask and friends). complyActivityFlags() calls Task.performClearTop() when the launch has FLAG_ACTIVITY_CLEAR_TOP or the target is singleTask, singleInstance or singleInstancePerTask. Every Activity above T is finished, and T gets the new intent through deliverNewIntent().
  • The CLEAR_TOP catch. In Task.clearTopActivities(), if T itself is standard and the launch has no FLAG_ACTIVITY_SINGLE_TOP, T is finished too and created again.
  • Replace the task. NEW_TASK | CLEAR_TASK empties the whole task first (performClearTaskForReuse), so T becomes its new root.

5. Deliver

A reused Activity is paused if it was resumed, gets onNewIntent(intent), then resumes. A new Activity goes through onCreate() as usual. Either way, the task that holds it is moved to the front.

Why it helps

  • “My startActivityForResult() returned RESULT_CANCELED instantly.” The launch was given a new task while a result was expected, so the system cancelled the result before the screen even opened.
  • “singleTask didn’t create a separate task.” Same affinity as the caller. Set android:taskAffinity, or accept that the “task search” finds your own task.
  • “The screen showed old data after being reused.” onCreate() didn’t run; onNewIntent() did. Handle the new intent there, and call setIntent() if later code reads getIntent().
  • “Back went somewhere unexpected.” Each task has its own back stack. A singleInstance screen sits alone in its task, so Back from it returns to whichever task was in front before.
  • “Two copies of the same screen.” standard (or a singleTop that wasn’t on top). Decide whether you want singleTop, CLEAR_TOP | SINGLE_TOP, or a navigation-level fix.

The map

Idea Where it lives (AOSP / SDK)
The four modes in the manifest android:launchMode, ActivityInfo.launchMode
Mode numbers ActivityInfo.LAUNCH_MULTIPLE (standard), LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_INSTANCE_PER_TASK
Which task the app “belongs to” android:taskAffinity, ActivityInfo.taskAffinity
One launch, end to end ActivityStarter.startActivityInner()
Forcing a new task ActivityStarter.setInitialState(), computeLaunchingTaskFlags()
Finding a task to reuse ActivityStarter.resolveReusableTask(), RootWindowContainer.findTask() / findActivity()
singleTop reuse ActivityStarter.deliverToCurrentTopIfNeeded()
Clear top, clear task ActivityStarter.complyActivityFlags(), Task.performClearTop(), clearTopActivities()
The callback you get Activity.onNewIntent(), setIntent()
Cancelled results ActivityStarter.sendNewTaskResultRequestIfNeeded()
Non-Activity context check ContextImpl.startActivity()
Seeing it on a device adb shell dumpsys activity activities

Edge cases

  • Same affinity, same task. Every Activity’s default taskAffinity is the app’s package name. So FLAG_ACTIVITY_NEW_TASK or singleTask from inside your own app usually finds the caller’s own task, and nothing looks different. Give T a different taskAffinity to actually see a second task.
  • singleInstance looks for itself, not an affinity. Its task only ever holds that one Activity, so the real question in step 3 is “is T already running?”. If not, it gets a fresh task even when a task with the same affinity exists.
  • Anything started from a singleInstance Activity gets NEW_TASK added, because it can’t join that task.
  • The flag can just bring a task forward. With FLAG_ACTIVITY_NEW_TASK, if a task is already running for the Activity you are starting, Android brings that task to the front in its last state instead of starting a new instance. This is how launchers behave.
  • Results and new tasks don’t mix. If the intent carries FLAG_ACTIVITY_NEW_TASK and you used startActivityForResult(), the result is cancelled immediately (“Activity is launching as a new task, so cancelling activity result.”). And a launch that expects a result never reuses an existing task.
  • Starting from a non-Activity context. ContextImpl.startActivity() throws “Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag”, except for apps targeting Android 7.0 to 8.1 (API 24 to 27), where the check is skipped and the system adds NEW_TASK itself.
  • Flags can stand in for modes. FLAG_ACTIVITY_SINGLE_TOP behaves like singleTop, and FLAG_ACTIVITY_CLEAR_TOP gives you the “destroy everything above it” step without singleTask.
  • Android 12 added singleInstancePerTask. The Activity is always the root of its task and other Activities can stack above it. Unlike singleInstance, it can have several instances, each in its own task, when the intent sets FLAG_ACTIVITY_MULTIPLE_TASK or FLAG_ACTIVITY_NEW_DOCUMENT.
  • singleTop needs a live top. The reuse check requires the top Activity to be attached to a process and to belong to the same user; otherwise a new instance is created.

Cross questions

The questions that come up about launch modes, from screening calls to whiteboard rounds. Try each one before you open the answer.

T is standard. From B you call startActivity(T) twice. How many Ts are there?

Two. standard never reuses, not even when a T is already on top. The stack is A › B › T › T, and Back has to be pressed twice to leave.

T is singleTop and the stack is A › T › B. What does startActivity(T) do?

It creates a second T: A › T › B › T. singleTop only looks at the very top of the stack, and B is there.

T is singleTask and the stack is A › T › B › C. What happens, and which callbacks run?

B and C are destroyed, so the stack becomes A › T. T is not recreated: it gets onNewIntent() and then onResume(). getIntent() still returns the old intent unless you call setIntent(intent) in onNewIntent().

You made an Activity singleTask, but launching it from your own app never creates a new task. Why?

Every Activity's default taskAffinity is the package name, so the task Android finds is the one you are already in. Give the Activity its own taskAffinity if it should live in a separate task.

T is singleInstance. T starts a standard Activity D. Where does D go?

Not into T's task, because nothing else can join it. D opens as if the intent had FLAG_ACTIVITY_NEW_TASK: in a task matching D's affinity, usually the app's main task.

Why does startActivity() from a Service or the application Context fail without a flag?

A non-Activity context has no task to put the new Activity in. Android throws an AndroidRuntimeException unless the intent has FLAG_ACTIVITY_NEW_TASK, which tells it to find or create a task.

What is the difference between singleTask and FLAG_ACTIVITY_CLEAR_TOP on a standard Activity?

Both destroy the Activities above T. With CLEAR_TOP alone, a standard T is destroyed too and created again with the new intent. Add FLAG_ACTIVITY_SINGLE_TOP, or use singleTask, to keep the instance and get onNewIntent() instead.

A notification opens a detail screen. How do you make Back go to the app's home screen instead of closing the app?

Build a back stack for the notification's PendingIntent with TaskStackBuilder (or a Navigation deep link), so the task opens as Home › Detail rather than Detail alone.

Which code actually decides what a launch does?

ActivityStarter in the system server (com.android.server.wm). computeLaunchingTaskFlags() decides whether the launch needs a task search, resolveReusableTask() finds the task, and deliverToCurrentTopIfNeeded() and complyActivityFlags() decide between reuse, clear-top and create.

Your startActivityForResult() gets RESULT_CANCELED before the screen even shows. Why?

The intent has FLAG_ACTIVITY_NEW_TASK. A new task can't return a result to another task, so the system sends RESULT_CANCELED immediately and launches the Activity without a link back to you.

What does FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK do?

It finds (or creates) the target's task, removes every Activity in it, and starts T as the new root. It is the usual way to "log out": the old back stack can't be reached with Back any more.

Is standard a real constant?

In code it's ActivityInfo.LAUNCH_MULTIPLE (value 0), which is a good description: multiple instances are allowed. The manifest value is standard.

How do you check what a launch really did on a device?

Run adb shell dumpsys activity activities. It prints every task with its affinity, root intent and stack of Activities, so you can compare the device with the tree.

Revision: key points

  1. Every launch answers two questions: which task, and new or reused.
  2. A task search happens when the launch ends up with NEW_TASK: target singleTask/singleInstance, caller singleInstance, no calling Activity, or the flag itself.
  3. The task is found by taskAffinity (default: the package name), except for singleInstance, which looks for itself.
  4. standard (LAUNCH_MULTIPLE) always creates; singleTop reuses only the top; singleTask clears everything above T; singleInstance lives alone.
  5. Reuse calls onNewIntent(); call setIntent() if later code reads getIntent().
  6. CLEAR_TOP on a standard T recreates it, unless SINGLE_TOP is also set.
  7. NEW_TASK | CLEAR_TASK replaces the whole task: the usual log-out flow.
  8. NEW_TASK and startActivityForResult() don’t mix: the result is cancelled at once.
  9. Check what really happened with adb shell dumpsys activity activities.

Then close the page and try the cross questions from memory.

The fine print

The low-level walk-through follows ActivityStarter on AOSP main (October 2026). Method names move between Android releases, and device makers can change the window manager, but the decisions themselves have been stable for years. When something surprising happens, adb shell dumpsys activity activities shows what the device actually did.

Part of the internals series: why read internals, WorkManager, ViewModel, process death and saved state.