태스크(Task)
태스크는 액티비티 스택에 대한 메타 데이터와 여러 정보의 콜렉션이다. 앱의 런처 아이콘을 클릭하면 안드로이드 시스템에서 실제로 수행하는 일은 재개(resume)할 이전의 기존 작업을 찾는 것이다. 만약 어느 태스크도 찾지 못했다면 새로 시작된 액티비티를 태스크의 백스택의 루트 액티비티로 설정하여 새로운 태스크가 생성된다.
백 스택(Back Stack)
먼저 안드로이드에서 Stack은 액티비티가 순서대로 저장되어 관리되는 공간을 의미한다. 뒤로가기를 누를 경우 최상단의 액티비티를 제거(pop)한다. 혹은 startActivity()를 통해 새로운 활동을 최상단에 추가하여 새 액티비티가 기존의 최상단 액티비티를 가릴 경우 기존 액티비티는 일시 중지된다.
태스크: 다른 앱의 액티비티와의 관계
앱을 개발하거나 이용하다보면 다른 앱을 intent를 통해 실행시키는 경우가 존재한다. 예를 들어, 메신저 앱과 갤러리 앱이 있다고 가정하고, 다음 시나리오를 확인해보자
- 메신저 앱에서 사진 추가 버튼을 누를 경우 intent를 통해 갤러리 앱을 실행한다.
- 실행된 갤러리 앱의 액티비티에서 사진을 선택하고, 이 사진은 메신저에 첨부되어 전송된다.
이 경우, 갤러리 앱의 액티비티는 메신저 앱의 태스크에 포함된다. 즉, 태스크에는 여러 앱의 액티비티가 존재할 수 있다는 점이다. 태스크는 사용자 관점에서 보는 앱 단위이기 때문이다.
Task Affinity
Activity 마다 정해진 taskAffinity가 있다. 기본적으로 앱의 패키지 명을 따른다. 이 task affinity는 어느 한 액티비티를 실행할 때 어떤 태스크에 속하게 실행할 것인지 지정하는 것이다. 예를 들어, 내가 만든 앱의 activity의 taskAffinity를 유튜브로 설정하면 유튜브의 task로 내 액티비티가 실행된다.
LaunchMode
LaunchMode는 안드로이드에서 액티비티를 실행할 경우 스택에 쌓이게 되는데 이때 액티비티를 어떠한 방식으로 스택에 쌓을 건지 LaunchMode를 통해 기술할 수 있다. 이는 Manifest의 activity 태그 내에서 설정할 수 있다.
LaunchMode의 종류
LaunchMode는 다음과 같이 4가지가 존재한다.
- standard
- singleTop
- singleTask
- singleInstance
그리고 다시 인스턴스화 가능 횟수에 따라 다음과 같이 분류할 수 있다.
- 한 태스크에 여러 번 인스턴스화 가능: standard, singleTop
- 한 태스크에 단 한 개의 인스턴스만 존재: singleTask, singleInstance
위를 쉽게 설명하면 한 태스크에 A->B->A 등으로 스택에 서로 다른 A가 여러 개 쌓일 수 있는지를 의미한다. 아래는 모드 별 자세한 설명이다.
기본적으로 singleTask와 singleInstance는 특수 목적용이다.
standard
Default로 설정되는 모드이다. 시스템은 항상 새로운 액티비티를 생성하게 된다.
singleTop
해당 모드는 작업 스택 top에 X라는 액티비티가 존재할 때, X를 실행시키면 기존 액티비티를 재활용하고 onNewIntent()를 호출한다. 하지만 여전히 여러 액티비티가 생성될 수 있음을 유의해야 한다. 다음 상황에서 Activity 3을 실행하고 다시 Activity 2를 실행하면 1->2->3->2 순으로 스택에 존재하게 된다. (참고로 onNewIntent() 후에는 onResume()이 호출된다.)
singleTask
위의 설명처럼 다중 인스턴스가 존재하지 않는다. 그리고, 오직 태스크(스택)의 루트에만 존재할 수 있다.
위 상황에서는 singleTask인 Activity 3을 실행한 경우이다. Activity 3은 오직 태스크의 루트에만 존재할 수 있기 때문에 아예 새로운 태스크를 하나 더 만들어서 해당 태스크에 루트로 추가되었다. (참고로 Activity 3을 다시 실행하면 Activity 3이 이미 태스크의 루트로 존재하기 때문에 해당 액티비티에서 onNewIntent()가 수행된다.)
singleInstance
singleTask와 마찬가지로 다중 인스턴스로 존재할 수 없다. 큰 차이점은 하나의 태스크에 하나의 액티비티만 존재할 수 있다.
위 상황은 singleInstance인 Activity 3을 실행하고 다시 Activity 3을 실행한 결과이다. singleInstance는 한 태스크에 하나의 singleInstance 액티비티만 존재할 수 있기 때문에 위와 같은 결과가 발생했다.
Intent의 Flag
어느 액티비티나 서비스 같은 컴포넌트를 Intent를 통해 실행하게 된다. 이 때 flag 값을 주어 액티비티를 어떠한 방식으로 실행시킬 지 결정할 수 있다. 마치 launch mode와 유사하게 동작한다. 가장 자주 사용하는 flag만 아래에 소개한다.
- FLAG_ACTIVITY_CLEAR_TOP : 호출하는 액티비티가 스택에 존재할 경우 해당 액티비티를 최상위로 올리고, 스택에 존재하는 기존 액티비티는 모두 제거한다.
- FLAG_ACTIVITY_NO_HISTORY: 액티비티가 스택에 존재하지 않도록 한다.
- FLAG_ACTIVITY_SINGLE_TOP: 호출하는 액티비티가 이미 최상단에 존재할 경우 새로 시작하기 않고 재활용한다.
- FLAG_ACTIVITY_NEW_TASK: 새로운 태스크를 생성하고 그 태스크에 호출하는 액티비티를 추가한다. 단, 기존에 존재하는 태스크 중에 생성하려는 액티비티와 동일한 task affinity를 가진 태스크가 존재한다면 그 태스크에 추가된다. (무조건 새로운 태스크를 생성하게 되는 것은 아니라는 의미이다.)
- FLAG_ACTIVITY_MULTIPLE_TASK: 위의 FLAG_ACTIVITY_NEW_TASK와 같이 사용되며, 같이 사용할 경우 호출하는 액티비티는 무조건 새로운 태스크의 루트 액티비티로 생성된다.
LaunchMode와 Intent Flag 설정 선택 요령
가장 큰 차이점은 LaunchMode는 XML에서 정의하고 Intent Flag는 실제 자바, 코틀린 코드 라인에서 명시한다는 점이 다르다. 이는 결국 정적이냐 동적이냐의 차이이다. 즉, 다음과 같은 기준을 세울 수 있다.
- 액티비티가 어디에서 실행되든 같은 방식으로 실행되어야 한다. -> LaunchMode에서 설정
- 액티비티를 실행할 때 실행되는 상황에 따라 서로 다른 방식으로 실행되는 경우가 존재한다 -> Intent Flag로 설정
(참고로 FLAG_ACTIVITY_NO_HISTORY 등은 LaunchMode가 아닌 noHistory 옵션을 주어야 한다. 다른 여러 플래그도 이런 차이점이 있을 수 있음을 유의해야 한다.)
참고
'안드로이드' 카테고리의 다른 글
[Android] Fragment 잘 사용하기 (0) | 2022.08.14 |
---|---|
뷰모델(ViewModel)에서 데이터를 로딩하는 다양한 방법 (0) | 2021.10.02 |
[안드로이드] PendingIntent란? (0) | 2021.07.26 |
[안드로이드] Retrofit으로 가져온 데이터를 디바이스에 캐싱하기 (0) | 2021.07.24 |
[Android] Coroutine, Retrofit을 활용한 비동기 네트워킹 처리 중 에러 핸들링 (0) | 2021.07.17 |