Android/학습

[Android] Launch Model(실행모드) 알아보기 (Task와 함께!)

한때미 2026. 7. 5. 02:56

 

이전 포스팅

 

https://androidhelper.tistory.com/50

 

[Android] 천천히 알아보는 Android Task

이전 포스팅 https://androidhelper.tistory.com/49 [Android] 가볍게 시작하는 Android Task이전에 fragment Manager에 대해 알아보면서 간단하게 백 스택 구조에 대해 알아본 적이 있다. https://androidhelper.tistory.com/28 [

androidhelper.tistory.com

 


 

일반적인 동작에서는 모든 Activity를 하나의 Task에 배치하여 백스택을 관리한다. 이는 후입선출(LIFO)로 관리된다.

하지만, 종종 이 동작을 앱 요구사항에 맞게 커스텀하고자 할 때가 있다.

 

오늘은 이러한 Activity 및 Task에 대한 동작을 수정하는 방법에 대해 알아보도록 하자.

 

 

 


 

Launch Mode (실행 모드)

launch mode를 사용하면 새로운 Activity의 인스턴스가 현재 Task에 연결되는 방식을 정의할 수 있다.

다음과 같은 두 가지 방법으로 정의할 수 있으며, 각 특징은 다음과 같다.

 

  • Manifest 파일에 정의
    • Manifest 파일에 정의된 activity에 launch mode를 설정.
    • 해당 Activity가 실행될 때 Task에 어떻게 연결될지 정의.

 

  • Intnet flags 사용
    • Intent에 해당 flag를 포함시켜 startActivty를 실행.
    • startActivity()를 호출할 때, 호출되는 새 Activity가 현재 Task에 어떻게 연결될지 결정.
    • 동일한 종류의 정책일 경우 Manifest에 선언된 요청보다 우선적으로 처리된다.

 

💡 참고: manifest 파일에서 사용할 수 있는 일부 Launch Mode는 Intent의 flag로 사용할 수 없다. 마찬가지로, Intentflag로 사용할 수 있는 일부 Launch Modemanifest에서 정의할 수 없다.

 

 


Manifest 파일을 사용하여 Launch Mode 정의

 

Manifest 파일에서 Activity를 선언할 때, 

<activity> 요소의 launchMode속성을 사용하여 Activity가 Task와 어떻게 연결되는지 지정할 수 있다.

 

<application
    ...>

    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:launchMode="standard">

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

    </activity>

</application>

 

Launch Mode 속성에 할당할 수 있는 실행 모드는 다섯 가지이다.

 

 

1. "standard"

기본적인 실행 모드(Launch Mode)로, 시스템은 Activity를 시작한 Task 안에 새로운 Activity 인스턴스를 생성하고, 그 Intent를 새 인스턴스에 전달한다.

 

여기서 Activity를 시작한 Task 안이란, startActivity()를 호출한 Activity가 속한 현재 Task 안에 새로운 Activity 인스턴스를 생성한다는 의미이다.

 

그렇기 때문에, Activity는 여러 번 인스턴스화될 수 있으며, 각 인스턴스는 서로 다른 Task에 속할 수도 있고, 하나의 Task에 동일한 Activity의 여러 인스턴스가 있을 수 있다.

 

standard에서는 새로운 Task를 만들지 않는다.
startActivity()를 호출한 현재 Task에 새 Activity를 추가한다.

 

  • 현재 Task 안에 Activity의 인스턴스가 생성한다.
  • 항상 새 인스턴스가 만들어진다.
  • 같은 Activity의 인스턴스가 여러 개 존재할 수 있다.
  • 여러 Task에도 Activity의 인스턴스가 각각 존재할 수 있다.

 

 

2. "singleTop"

현재 Task의 최상단에 해당 Activity의 인스턴스가 이미 존재한다면, 시스텀은 새 인스턴스를 생성하는 대신 해당 인스턴스의  onNewIntent() 메서드를 호출하여 Intent를 해당 인스턴스로 전달한다.

 

즉, 현재 Task의 최상단 인스턴스의 Activity가 실행시키고자 하는 Activity라면, 인스턴스를 새로 생성하지 않고 현재 최상단에 있는 인스턴스의 Activity의 onNewIntent()를 Intent로 호출하는 것이다.

 

override fun onNewIntent(intent: Intent?)

 

 

즉, Activity는 여러 번 인스턴스화될 수 있으며, 각 인스턴스는 서로 다른 Task에 속할 수 있고, 하나의 Task는 여러 인스턴스를 가질 수 있다(단, 백 스택 최상단의 Activity가 기존 인스턴스가 아닌 경우).

 

현재 Task의 Top에 같은 Activity가 있을 때만 기존 인스턴스를 재사용(onNewIntent() 호출)하고,
그렇지 않으면 standard와 동일하게 새로운 Activity를 생성한다.

 

 


 

Launch Mode의 "standard"와 "singleTop" 비교, 2번 시나리오는 동일한 것을 볼 수 있다.

 

 

💡 참고: 새로운 Activity 인스턴스가 생성된 경우에는 사용자가 Back 버튼(또는 뒤로 가기 제스처)을 눌러 이전 Activity로 돌아갈 수 있다. 하지만 기존 Activity가 onNewIntent()를 통해 새로운 Intent를 처리한 경우에는, Back 버튼을 눌러도 onNewIntent()가 호출되기 전의 그 Activity 상태로는 돌아갈 수 없다.

 

onNewIntent()를 통해 새로운 Intent를 처리한 것새로운 인스턴스가 생성되어 백스택(Task)에 쌓인 것이 아닌,

이미 백스택(Task)에 있는 인스턴스가 새로운(다른) Intent를 받아 갱신된 것이기 때문에,

해당 화면에서 back 버튼(및 제스처)을 통해 뒤로 갈 경우 이전에 쌓였던 다른 Activity의 인스턴스가 보이게 되는 것이다.

 

 

즉, Launch Mode의 "singleTop"일 때, 예시 이미지의 1번 시나리오의 A-B-C-D의 경우 바로 C 화면이 나오게 되는 것이다.

 

 

 

3. "singleTask"

시스템은 새로운 Task의 루트에 Activity를 생성하거나, 같은 affinity를 가진 기존 Task에서 해당 Activity를 찾는다.

 

이 말은, 시스템은 해당 Activity가 이미 존재하는 Task가 있는지 찾고, 없으면 새로운 Task를 만들어 그 루트(Activity의 첫 번째 Activity)로 생성한다는 것이다.

affinity는 Launch Mode 이후에 다뤄보도록 하자.

새로운 Task를 생성하는 경우에는 루트 Activity로 생성되지만, 이후에는 일반 Activity가 그 위에 추가될 수 있다.

 

그리고 해당 Activity 인스턴스가 이미 존재하면, 새로운 인스턴스를 생성하지 않고 기존 인스턴스의 onNewIntent()를 호출하여 Intent를 전달한다.

그리고 그 Activity 위에 쌓여 있던 모든 Activity는 제거(destroy)된다.

 

이는, "singleTask" 동작이 Task 안에 해당 Activity는 하나만 존재하도록 보장할 수 있게 한다.

 

 

💡 참고: Activity가 새로운 Task에서 시작되더라도, Back을 누르면 그 Task가 종료되고 사용자는 새 Task를 열기 전까지 보고 있던 화면(이전 Activity)으로 돌아간다. 

 


 

그런데 해당 참고 상황과 다른 "singleTask"에 대한 다른 예시를 한번 살펴보고 가도록 하자,

 

 

Android 브라우저 앱은 Activity의 <activity> 요소에 Launch mode를 singleTask로 선언하여 웹 브라우저 Activity를 항상 자체 Task에서 실행되도록 선언한다.

 

startActivity(Intent(Intent.ACTION_VIEW, url))

 

 

즉, 앱에서 안드로이드 브라우저를 열도록 요청하는 Intent를 발생시키면 브라우저 Activity는 앱과 동일한 Task에 배치되지 않는다.

 

대신, 브라우저를 위한 새로운 Task가 시작되거나,

브라우저가 이미 백그라운드에서 실행 중인 Task가 있는 경우, 해당 Task가 앞으로 나와 새로운 Intent를 처리한다.

 

즉, 앱이 브라우저를 열기 위한 Intent를 보내더라도, 브라우저 Activity는 앱 Task에 추가되지 않는다.

 

 

새로운 Task에서 시작하든, 시작했던 Task과 동일한 Task에서 시작하든 관계없이,

시스템은 뒤로 가기 버튼과 제스처는 항상 사용자를 이전 Activity로 이동시킨다.

 

 

하지만 singleTask 실행 모드가 지정된 Activity의 인스턴스가 백그라운드 Task에 존재하는 경우,

시스템은 Activity의 인스턴스를 새로 만드는 것이 아닌 (Activity 인스턴스가 포함된)Task 전체를 포그라운드로 가져온다.

 

이때 백 스택에는 포그라운드로 가져온 Task의 모든 액티비티가 포함된다.

즉, 새 Browser 하나만 보이는 것이 아니라 Browser Task 전체가 살아있는 상태로 올라오게 되는 것이다.

 

 

그림으로 보면 다음과 같다.

 

"singleTask" 실행 모드를 가진 Activity가 백 스택에 추가되는 방식

 

이 경우 사용자가 Back 버튼(및 제스처)을 할 경우 이전 Activity가 아닌 현재 포어그라운드로 올라온 Task의 백스택에 있던 이전 Activitiy를 보게 되는 것이다.

 

만약 이때 실행되는 Activity가 Y가 아니라 X라면 X 위에 있는 Y 인스턴스는 제거되었을 것이다.

 

 

 

4. "singleInstance"

해당 Launch Mode는 "singleTask"와 동일하나, 그 Activity가 있는 Task에는 다른 Activity를 실행시키지 않습니다.

 

그 Activity는 항상 자기 Task의 유일한 Activity이다

이 Activity에서 시작하는 다른 Activity들은 모두 해당 Activity의 Task와는 별도의 Task에서 열린다.

 

singleInstance는 singleTask처럼 인스턴스를 하나만 유지하지만,
해당 Activity는 자기 Task에 혼자만 존재하며,
그렇기 때문에 Activity가 시작하는 다른 Activity들도 모두 별도의 Task에서 실행되게 된다.

 

 

 

5. "singleInstancePerTask"

이 Activity는 Task의 루트 Activity(첫 번째 Activity) 로만 실행될 수 있다.

 

즉, Task를 생성한 첫 번째 Activity여야 하기 때문에, 따라서 하나의 Task 안에는 이 Activity 인스턴스가 하나만 존재할 수 있다.

 

다만, 만약 FLAG_ACTIVITY_MULTIPLE_TASK 또는 FLAG_ACTIVITY_NEW_DOCUMENT를 사용한 경우 "singleInstancePerTask"는 "singleTask"와는 다르게 서로 다른 Task에서 해당 Activity의 인스턴스로 실행될 수 있다.

 

해당 flag를 사용하지 않는 경우 singleTask과 동일하게 동작한다.

 

 


 

 

"singleTask"와 "singleInstancePerTask"는 실행하려는 Activity의 기존 인스턴스가 현재 Task에 이미 존재하면 새로운 인스턴스를 생성하지 않고 기존 인스턴스의 onNewIntent()를 호출한다.

 

이때 기존 Activity를 스택의 맨 위로 이동시키는 것이 아니라, 그 Activity 위에 쌓여 있던 모든 Activity를 종료하여 제거한다.

 


따라서 예를 들어 Back Stack이 A → B → C이고 A가 "singleTask" 또는 "singleInstancePerTask"라면,

A를 다시 실행했을 때 B와 C는 모두 종료되고,

기존 A가 onNewIntent()를 통해 Intent를 전달받아 최종적으로 Back Stack은 A만 남게 된다.

 

 

"singleTask"와 "singleInstancePerTask"의 동작 방식을 이미지로 보면 다음과 같다.

 

 


Intent Flag를 사용하여 Launch Mode 정의

Activity를 시작할 때, startActivity() 메서드에 전달하는 Intent에 flag를 포함시켜 Activity와 Task의 기본 연결을 수정할 수 있다.

 

val intent = Intent(this, BrowserActivity::class.java).apply {
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}

startActivity(intent)

 

기본 동작을 수정하는 데 사용할 수 있는 flag는 다음과 같다.

 

 

FLAG_ACTIVITY_NEW_TASK

 

시스템은 새로운 Task에서 Activity를 시작한다.

 

시작하려는 Activity이미 실행 중인 Task가 있는 경우, 해당 Task가 마지막 상태를 복원한 상태로 포그라운드로 전환되고,

Activity는 onNewIntent() 메서드에서 새로운 Intent를 수신한다.

 

즉, 시스템은 현재 Task가 아닌 Task에서 Activity를 실행한다.
기존 Task가 존재하면 해당 Task를 재사용하고, 없으면 새로운 Task를 생성한다.

 

이는 앞 섹션에서 설명한 "singleTask" launchMode 값과 동일한 동작을 나타낸다.

 

그렇지만 "singleTask"와 중요한 차이가 있다.

 

"singleTask"는 해당 Activity 인스턴스가 이미 존재하면, 새로운 인스턴스를 생성하지 않고 기존 인스턴스의 onNewIntent()를 호출하여 Intent를 전달되면서 그 Activity 위에 쌓여 있던 모든 Activity는 제거(destroy)된다.

 

하지만, FLAG_ACITVITY_NEW_TASK는 그저 기존 Task가 존재하면 해당 Task를 전경으로 가져오고 기존 Activity에 onNewIntent()를 전달하며, 이 후의 동작은 선언된 launch Mode에 따라 진행된다.

 

이것이 FLAG_ACITVITY_NEW_TASK는 flag 속성이기 때문에 특정 startActivity() 호출에만 적용되는 실행 옵션임을 보여준다.

 

 

FLAG_ACTIVITY_SINGLE_TOP

 

시작하려는 Activity가 현재 실행 중인 Activity(백 스택의 최상단에 있는 Activity)인 경우,

Activity 인스턴스를 생성하는 대신 기존 인스턴스가 onNewIntent()를 호출받게 된다.

 

이는 앞 섹션에서 설명한 "singleTop" launchMode 값과 동일한 동작을 나타낸다.

 

 

FLAG_ACTIVITY_CLEAR_TOP

 

현재 Task에서 이미 실행 중인 Activity를 시작하려는 경우,

해당 Activity의 새 인스턴스를 실행하는 대신 시스템은 그 위에 있는 다른 모든 Activity를 종료한다.

그런 다음 onNewIntent()를 통해 현재 맨 위에 있는 재개된 Activity 인스턴스에 Intent를 전달한다.

 

Manifest의 launchMode 속성에는 이러한 동작의 설정 값이 없다.

 

 

FLAG_ACTIVITY_CLEAR_TOP은 FLAG_ACTIVITY_NEW_TASK와 함께 가장 자주 사용된다.

두 Flag를 함께 사용하면, 다른 Task에 이미 존재하는 Activity를 찾아 그 Task를 포어그라운드로 가져오고,

해당 Activity가 Intent를 처리할 수 있도록 만든다.

 

 


 

이는 언뜻 보면 "singleTask" 동작과 유사해 보이지만,

 

 

대상 Activity의 launchMode가 standard라면,

그 Activity 역시 Back Stack에서 제거되고, 새로운 인스턴스가 생성되어 전달된 Intent를 처리한다.

 

그 이유는 standard launchMode에서는 새로운 Intent가 들어올 때마다 항상 새로운 Activity 인스턴스를 생성하기 때문이다.

 

동일 Task에서 해당 flag를 사용할 경우 각 launch Mode에 따른 동작 차이

 

 

FLAG_ACTIVITY_NEW_TASK를 같이 사용했을 경우 각 launch Mode에 따른 동작 차이

 

 

참고적으로, FLAG_ACTIVITY_MULTIPLE_TASK와 FLAG_ACTIVITY_NEW_TASK는 task의 재사용 유무 차이이다.

 

 

FLAG_ACTIVITY_CLEAR_TOP은 기존 Activity 위의 Back Stack을 정리하는 Intent Flag이며,
대상 Activity의 재사용 여부는 launchMode에 따라 결정된다.

 

 

 

 

 


추가적으로 알아봐야 하는 부분

 

추가적으로 알아보면 좋을 만한 것들

  • 최근 항목 화면
    • +) android:documentLaunchMode
  • <activity> 요소
    • Launch Mode의 그 밖의 설정 방법
  • FLAG_ACTIVITY_NEW_DOCUMENT의 의미, FLAG_ACTIVITY_MULTIPLE_TASK와 차이

 

 

참고 자료