본문 바로가기
깡샘 코틀린

13-4 태스크 관리

by 농농씨 2023. 7. 1.

태스크(task) 관리액티비티를 어떻게 생성하고 관리하는지를 제어하는 일을 의미한다. 시스템에는 액티비티의 태스크를 유지하는 기본 규칙이 있으며 일반적으로는 이 기본 규칙을 그대로 이용하지만 특정한 상황에서 개발자가 액티비티의 태스크를 관리해야 한다면 설정을 추가할 수도 있다.

 

시스템에서 태스크 관리

액티비티 태스크란? 앱이 실행될 때 시스템에서 액티비티의 각종 정보를 저장하는 공간

 

A 앱이 A_OneActivitiy, A_TwoActivity 두 액티비티로 구성되어있다고 가정하자.

사용자가 앱을 실행해 A_OneActivity 화면이 나오고 다시 A_OneActivity에서 인텐트로 A_TwoActivity를 실행했다고 생각해보자. 그러면 액티비티 객체가 2개가 생성되고 시스템은 이 액티비티가 실행되었다는 정보를 저장하려고 하나의 태스크를 만든다.

그러면 A앱 태스크 안에 A_OneActivity와 A_TwoActivity의 정보가 태스크에 올라간다. 태스크에서 위쪽에 있는 액티비티인 A_TwoActivity가 화면에 출력된다. 이 상태에서 사용자가 홈 버튼을 눌러 런처 화면으로 나갔다가 앱을 다시 실행하면 저장된 태스크 정보가 그대로 적용되어 화면에는 태스크 위쪽에 있는 A_TwoActivity 액티비티가 나온다.

그런데 사용자가 기기의 뒤로가기 버튼을 누르면 이 태스크에서 위쪽에 있는 액티비티를 종료하고 다시 태스크 아래쪽에 있는 액티비티부터 화면에 출력한다. 따라서 화면에는 A_OneActivity가 출력된다.

 

그렇다면 실행하는 앱마다 태스크는 하나일까? No! 앱과 앱이 연동되어 실행되는 구조를 알아보자.

A앱과 마찬가지로 액티비티 두개로 이루어진 B 앱이 있다고 치자.

사용자가 A앱을 실행해 A_OneActivity→A_TwoActivity→B_TwoActivity를 차례로 실행했다고 생각해보자. 사용자는 앱을 하나만 실행했지만 실제로는 2개 실행한 상태이다. 그런데 이때 액티비티의 실행 정보를 담는 태스크는 하나만 만들어진다.

B_TwoActivity는 B 앱의 액티비티지만 A 앱의 태스크에 등록된다. 여기서 태스크는 "사용자 관점에서" 프로그램의 논리적인 실행 단위라고 정리할 수 있다. 시스템 내부에서는 앱이 2개 실행되었지만 사용자 관점에서는 앱을 하나만 실행해 화면이 3개 나온 것이다.

 

그런데 이러한 상태에서 사용자가 런처 화면으로 나와 B 앱을 실행하면 어떻게 될까? 즉, 다음과 같은 순서!

  1. 사용자가 A 앱을 실행해 A_OneActivity 실행
  2. A_OneActivity에서 A_TwoActivity 실행
  3. A_TwoActivitiy에서 B_TwoActivity 실행
  4. 홈 버튼을 눌러 런처 화면을 빠져나옴
  5. 런처 화면에서 B 앱을 실행해 B_OneActivity 실행
  6. B_OneActivity에서 B_TwoActivity 실행

여기서 중요한 것은 사용자가 앱을 2개 실행했다는 것이고 B_TwoActivity는 2번 실행되었다는 사실이다. 즉, 인텐트로 같은 액티비티가 2번 실행되었다. 이러한 상황에서 앱의 태스크는 다음처럼 정보를 저장한다.

A앱 태스크 B앱 태스크
B_TwoActivity
A_TwoActivity
A_OneActivity

B_TwoActivity
B_OneActivity

사용자가 앱을 2개 실행했으므로 태스크도 2개가 만들어진다. 그런데 중요한 것은 A_TwoActivity에서 인텐트로 실행한 B_TwoActivity가 아직 종료되지 않은 상태에서 다시 B_OneActivity가 똑같이 B_TwoActivity를 인텐트로 실행했다는 것이다.

액티비티는 인텐트가 발생하면 무조건 객체를 생성한다. 이미 같은 액티비티가 실행되어 같은 객체가 있더라도 어디선가 다시 인텐트가 발생하면 또다시 (새로운 )객체가 생성되고 태스크 정보에 등록된다. 따라서 B_TwoActivity는 2번 생성되며 태스크에 각각 등록된다.

 

 

태스크 제어

시스템에서 태스크를 관리하는 방법을 이해했다면 이제는 시스템이 아닌 개발자가 원하는 대로 액티비티 객체가 생성되고 태스크에 등록되도록 제어하는 방법을 알아보자. 2가지 방법이 있다.

  • 액티비티가 등록되는 매니페스트 파일의 <activity> 태그의 launchMode를 이용한다.
  • 인텐트의 flags 정보를 설정하여 제어한다.

매니페스트 파일에서는 다음처럼 <activity> 태그의 launchMode 속성으로 실행 모드를 설정해주면 된다.

// 매니페스트 파일에서 launchMode로 제어
<activity android:name=".TwoActivity" android:launchMode="singleTop">

 

반면에 코드에서는 인텐트를 발생시키기 전에 인텐트의 flags 속성에 설정한다.

// 코드에서 flags 속성으로 제어
val intent = Intent(this, TwoActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
startActivity(intent)

두 방법 모두 같은데 <activity> 태그의 launchMode 속성을 이용하면 이 액티비티는 인텐트에 의해 항상 설정한 대로 생성되어 태스크에 등록되고, 인텐트의 flags 속성을 이용하면 이번 인텐트가 발생할 때에 한번만 적용되어 태스크에 등록된다.

 

그러면 launchMode에 설정할 수 있는 속성값을 알아봅시다~

 

스탠더드로 설정

실행 모드를 standard로 설정하면 설정하지 않은 기본값과 같다. 즉, 액티비티에서 인텐트가 발생하면 항상 객체가 생성되고 태스크에 등록된다. 

실행모드를 standard로 설정한 A_TwoActivity가 인텐트로 자신을 다시 실행했다고 하자.

이렇게 하면 A_TwoActivity 객체는 2개가 생성되고 태스크에 액티비티 정보가 2개가 등록된다.

A앱 A앱 태스크
A_OneActivity

     A_TwoActivity←    ↑
                   ↓                →
A_TwoActivity
A_TwoActivitiy
A_OneActivity

 

 

싱글 톱으로 설정

실행 모드를 singleTop으로 설정하면 액티비티 정보가 태스크의 위쪽에 있을 때 인텐트가 발생해도 객체를 생성하지 않는다. 원래 액티비티는 인텐트만 발생하면 무조건 객체가 생성되어야 하지만 singleTop 실행 모드로 설정한 액티비티가 태스크 위쪽에 있으면 어디선가 그 액티비티를 실행하는 인텐트가 발생해도 객체가 생성되지 않는다.

 

다음은 A_TwoActivity를 singleTop으로 설정했다고 가정해보자.

A앱 태스크
A_TwoActivity
A_OneActivity

태스크에서 A_TwoActivity가 위쪽에 있는 상황에서 어디선가 다시 인텐트로 A_TwoActivity를 실행해도 객체가 생성되지 않는다. 그 대신 기존 객체의 onNewIntent() 함수가 자동으로 호출된다.

// onNewIntent() 함수
override fun onNewIntent(intent: Intent?) {
	super.onNewIntent(intent)
}

위 함수를 액티비티에 재정의해 놓으면 singleTop으로 설정한 액티비티 객체가 태스크의 위쪽에 있을 때 인텐트로 자신을 다시 실행하면 자동으로 호출된다.(?)

 

그렇다면 singleTop으로 설정한 액티비티 객체가 맨 위가 아니라면?

A앱 A앱 태스크
A_OneActivity

                 A_TwoActivity    ←           
                          ↓                   ↑      
         A_ThreeActivity.      ↑
             ↓        →
A_TwoActivity
A_ThreeActivity

A_TwoActivitiy
A_OneActivity

이 상황에서 액티비티를 실행하는 인텐트가 발생하면 객체는 다시 생성된다. 결국 singleTop태스크의 위쪽에 있을 때에만 객체를 생성하지 않는다.

 

그렇다면 실전에서의 singleTop 사용예시?

액티비티가 화면에 출력되는 상황에서 똑같은 액티비티를 인텐트로 다시 실행하는 에를 알아보자. 대표적으로 알림을 들 수 있다.

카카오톡 채팅 알림 메시지가 온 경우를 가정해보자. 카카오톡 채팅 화면을 ChatActivity라고 하고 누군가와 메시지를 나누다가 다른 사람에게 새로운 메시지가 온 상황이다.

ChatActivity 화면에서 대화를 나누다가 새 메시지를 받으면 알림이 뜨고 사용자가 알림을 터치하면 해당 채팅방이 나타나 새로운 채팅방의 ChatActivity 화면이 나온다. 즉 알림을 터치하면 인텐트가 발생하고 그 인텐트로 ChatActivity가 실행된다.

이미 기존 채팅방에서 대화한 내용이 들어있는 ChatActivity객체가 생성되어 화면 상단에 있는 상황에서 다시 인텐트로 ChatActivity를 실행하는 상황이다.

스탠더드 태스크
ChatActivity → (새 채팅)
ChatActivity → (기존 채팅)

만약에 아무런 설정을 하지 않아 standard로 지정되면 ChatActivity 객체는 하나 더 생성되어 태스크에 다시 등록된다. 화면에는 새로 받은 메시지가 나오지만 사용자가 뒤로가기 버튼을 누르면 기존 채팅방을 보여주는 ChatActivity가 다시 나타난다.

앱이 이렇게 동작해야 한다면 상관없지만 일반적으로는 같은 ChatActivity 객체에서 대화 내용만 교체한다. 이럴 때 실행 모드를 singleTop으로 설정한다. 실행 모드를 singleTop으로 설정하면 인텐트가 다시 발생하더라도 객체가 다시 생성되지 않는다. 그 대신 onNewIntent() 함수에서 대화 내용만 바꾸면 된다.

싱글 톱 태스크
ChatActivity - 기존채팅 → 새 채팅

 

싱글 태스크로 설정

실행 모드를 singleTask로 설정하면 새로운 태스크를 만들어 등록한다. 그런데 singleTask 설정은 같은 앱에서는 적용되지 않으며 다른 앱의 액티비티를 인텐트로 실행할 때에만 적용된다. 따라서 사용자가 새로운 앱을 실행하지 않더라도 하나의 태스크를 다시 만들 때 사용한다. 기기에 따라 다르지만 태스크가 바뀌면 화면 전환 애니메이션 효과가 나타날 수 있으며, 결국 새로운 앱이 실행되는 것을 사용자에게 알리고 싶을 때 사용한다.

다음은 B_OneActivity의 실행 모드를 singleTask로 설정한 예이다.

A_TwoActivity가 B_OneActivity를 실행시킨다고 하자

A앱 태스크 B앱 태스크
A_TwoActivitiy
A_OneActivity
B_TwoActivitiy
B_OneActivity

standard 였으면 하나의 태스크에 액티비티 정보 4개가 등록되어야 하는데 singleTask로 설정했으므로 B_OneActivity부터는 새 태스크를 만들어 정보를 등록한다.

 

싱글 인스턴스로 설정

A앱 태스크 B앱 태스크 B앱 태스크
A_TwoActivitiy
A_OneActivity
B_OneActivity B_TwoActivitiy

실행 모드를 singleInstance로 설정하면 싱글 태스크처럼 새로운 태스크를 만들어 등록하는데, 그 태스크에는 해당 설정이 적용된 액티비티 하나만 등록된다. 그 위에 액티비티가 또 쌓이지 않는다는 뜻이다.

B_TwoActivity는 새로운 태스크에 등록된다. B_OneActivity는 태스크 하나를 차지하게 된다.

'깡샘 코틀린' 카테고리의 다른 글

섹션 0. 들어가기에 앞서  (0) 2023.07.02
13-5 액티비티 ANR 문제와 코루틴  (0) 2023.07.01
13-3 액티비티 제어  (0) 2023.07.01
13-2 액티비티 생명주기  (0) 2023.07.01
13-1 인텐트 이해하기  (0) 2023.06.30