Topic: 15 Understanding Launch Mode in Android

This is our Fifteenth topic from learn android from basic to advance series

Topic: 15 Understanding Launch Mode in Android

Hello devs, So Today we talk about Launch modes in Android. In Android, launch modes define how a new instance of an activity should be launched in relation to the existing activities in the application.

Types of Launch Modes

  1. Standard

  2. SingleTop

  3. SingleTask

  4. SingleInstance

Let's explore these launch modes one by one.

1. Standard:

This is the default launch mode. Every time you start an activity, a new instance of the activity is created and placed on top of the activity stack.

Use this launch mode when you want to create a new instance of the activity each time it is launched, regardless of whether an instance of the activity is already present in the stack.

Suppose we have A, B, C, and D activities and your activity B has standard launch mode. Now again launching activity B

We have four activities launched in the below order

A -> B -> C -> D

Activity C has the standard launch mode

Lets launch C again after D then the stack looks like below

A -> B -> C -> D ->C

We can see here that there are 2 instances of Activity C

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchB: Button = findViewById(R.id.button_launch_b)
        buttonLaunchB.setOnClickListener {
            val intent = Intent(this, ActivityB::class.java)
            startActivity(intent)
        }
    }
}
// ActivityB.kt
class ActivityB : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_b)

        val buttonLaunchBAgain: Button = findViewById(R.id.button_launch_b_again)
        buttonLaunchBAgain.setOnClickListener {
            val intent = Intent(this, ActivityB::class.java)
            startActivity(intent)
        }
    }
}

In this example:

  • MainActivity is the launcher activity with a button (button_launch_b) to launch ActivityB.

  • ActivityB has a button (button_launch_b_again) to launch itself again.

Assuming ActivityB is declared in the manifest with the standard launch mode:

<activity android:name=".ActivityB" android:launchMode="standard"/>

When you click the button in MainActivity to launch ActivityB, the activity stack becomes A → B, where A is MainActivity and B is ActivityB.

Now, when you click the button in ActivityB to launch another instance of ActivityB, the activity stack becomes A → B → B. Another instance of ActivityB is created and added to the top of the stack.

2. SingleTop:

In this mode, if the activity instance already exists at the top of the stack, the system routes the intent to that instance through onNewIntent() instead of creating a new instance.

Use this launch mode when you want to have a single instance of an activity at the top of the stack to handle incoming intents. It can be useful for scenarios like chat applications or media playback.

Case 1:

A -> B -> C -> D

Activity D has launch mode singleTop and if we launch D again then the activity stack looks as below

A -> B -> C -> D

As we can see the D is not launched again and the system will route the intent information through onNewIntent()

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchD: Button = findViewById(R.id.button_launch_d)
        buttonLaunchD.setOnClickListener {
            val intent = Intent(this, ActivityD::class.java)
            startActivity(intent)
        }
    }
}
// ActivityD.kt
class ActivityD : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_d)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        // Handle the new intent information here
    }
}

In this example:

  • MainActivity has a button (button_launch_d) to launch ActivityD.

  • ActivityD has the singleTop launch mode declared in the manifest.

Case 2:

A -> B-> C-> D

Activity C has launch mode singleTop and if we launch C on top of D then the activity stack looks as below

A -> B -> C -> D -> C

Here we can see that C is launched again as its not at the top of the task.

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchC: Button = findViewById(R.id.button_launch_c)
        buttonLaunchC.setOnClickListener {
            val intent = Intent(this, ActivityC::class.java)
            startActivity(intent)
        }
    }
}
// ActivityC.kt
class ActivityC : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_c)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        // Handle the new intent information here
    }
}

In this example:

  • MainActivity has a button (button_launch_c) to launch ActivityC.

  • ActivityC has the singleTop launch mode declared in the manifest.

In both cases, when you click the button in MainActivity to launch the respective activity, the behavior you described will be observed based on the launch mode specified for each activity.

3. SingleTask:

Here, a new task is always created, and the activity instance is placed at the root of this new task. If an instance of the activity exists in another task, the system routes the intent to the existing instance through onNewIntent().

Use this launch mode when you want to have a unique instance of an activity that serves as the entry point to your application or as a main screen. It is useful for scenarios like a home screen or a splash screen.

Suppose we have A, B, C activities(A →B →C ) and we are launching D that has a singleTask launch mode. In that case, the new instance of D will be created so the current state will look like this. (A →B →C →D)

Now let suppose if we launch B that also have has a singleTask launch mode then current state will look like this.

A →B

Here old instance gets called and intent data route through onNewIntent() callback. Also, notice that C and D activities get destroyed here.

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchD: Button = findViewById(R.id.button_launch_d)
        buttonLaunchD.setOnClickListener {
            val intent = Intent(this, ActivityD::class.java)
            startActivity(intent)
        }

        val buttonLaunchB: Button = findViewById(R.id.button_launch_b)
        buttonLaunchB.setOnClickListener {
            val intent = Intent(this, ActivityB::class.java)
            startActivity(intent)
        }
    }
}
// ActivityD.kt
class ActivityD : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_d)
    }
}
// ActivityB.kt
class ActivityB : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_b)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        // Handle the new intent data here
    }
}

In this example:

  • MainActivity is the launcher activity with buttons to launch ActivityD and ActivityB.

  • ActivityD has a singleTask launch mode.

  • ActivityB also has a singleTask launch mode.

When you click the button to launch ActivityD, a new instance of ActivityD is created and added to the activity stack: A → B → C → D.

Then, when you click the button to launch ActivityB, the existing instance of ActivityB is brought to the front, and its onNewIntent() method is called to handle the new intent data. The activity stack becomes: A → B. Activities C and D are destroyed because ActivityB has a singleTask launch mode, and launching it clears all activities above it in the stack.

4. SingleInstance:

This mode is similar to SingleTask, but the activity is launched into a new task with no other activities. It's always the single and only member of its task.The activity is always launched into a new task, and all other activities are removed from the stack.

Use this launch mode when you want to have a dedicated task for the activity, and you don’t want it to be mixed with other activities. It is suitable for scenarios like a dialer or a camera application.

Case 1:

Suppose you have A, B, and C activities(A →B →C) and your activity D has a singleInstance launch mode. In this case, if we launch D then D will be launch in the diffrent task. New task for D will be created.

Task1: A →B →C

Task2 : D (here D will be in the different task)

Now if you continue this and start E and D then Stack will look like

Task1: A →B →C →E

Task2: D

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchD: Button = findViewById(R.id.button_launch_d)
        buttonLaunchD.setOnClickListener {
            val intent = Intent(this, ActivityD::class.java)
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK // Set flag to start in a new task
            startActivity(intent)
        }

        val buttonLaunchE: Button = findViewById(R.id.button_launch_e)
        buttonLaunchE.setOnClickListener {
            val intent = Intent(this, ActivityE::class.java)
            startActivity(intent)
        }
    }
}
// ActivityD.kt
class ActivityD : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_d)
    }
}
// ActivityE.kt
class ActivityE : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_e)
    }
}
  • MainActivity launches ActivityD with the FLAG_ACTIVITY_NEW_TASK flag to start it in a new task.

  • ActivityD is launched in a separate task from MainActivity.

  • Then ActivityE is launched in the same task as MainActivity, so the activity stack looks like:

    Task1: A → B → C → E

    Task2: D

Case 2:

Suppose you have A, B, C activities in one task (A →B →C)and activity D is in another task with launch mode singleInstance. In this case, if we launch D again then we will receive the callback in the onNewIntent() method of D activity.

Task1: A →B →C

Task2: D (Here old instance gets called and intent data route through onNewIntent() callback)

Example:

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val buttonLaunchD: Button = findViewById(R.id.button_launch_d)
        buttonLaunchD.setOnClickListener {
            val intent = Intent(this, ActivityD::class.java)
            startActivity(intent)
        }
    }
}
// ActivityD.kt
class ActivityD : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_d)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        // Handle the new intent data here
    }
}
  • MainActivity launches ActivityD.

  • As ActivityD has a singleInstance launch mode, the existing instance of ActivityD is called, and onNewIntent() is invoked to handle the new intent data. No new instance of ActivityD is created.

  • The activity stack remains as:

    Task1: A → B → C

    Task2: D

Manifest Declaration:

Don't forget to declare these activities in your AndroidManifest.xml file along with their launch modes:

<activity android:name=".StandardActivity" android:launchMode="standard"/>
<activity android:name=".SingleTopActivity" android:launchMode="singleTop"/>
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>

Alright devs, It's time to wrap up this blog. I hope this blog helps you to understand Launch Mode in Android. Ok, then we meet on our next blog. In the next blog, we explore Serializable and Parcelable interfaces in Android


Connect with Me:

Hey there! If you enjoyed reading this blog and found it informative, why not connect with me on LinkedIn? 😊 You can also follow my Instagram page for more mobile development-related content. 📲👨‍💻 Let’s stay connected, share knowledge and have some fun in the exciting world of app development! 🌟

Check out my Instagram page

Check out my LinkedIn