2. 1. Activity Task 란?
Task란 Activity들의 Stack이라고 볼 수 있다.
이렇게 "PackageA_1 -> PackageA_2 -> PackageA_3" 는 하나의 그룹을
형성하게 되고,
프로그램의 UI 흐름을 이룬다.
안드로이드 Framework은 내부적으로 해당 순서를 기억한다.
3. 1. Activity Task 란?
"PackageA_3" Activity가 현재 화면에 보여지는 Activity이며,
"PackageA_3"가 종료되면 "PackageA_2"가 보여진다.
"PackageA_3"가 종료되고 "PackageA_1"이 보여 질 수는 없다.
이런 구조는 Stack의 구조와 동일하다.
안드로이드에서는 이것을 Task라는 명칭을 쓴다.
4. 1. Activity Task 란?
>> adb shell dumpsys activity 현재 Activity Stack의 구조를 출력
7. 1. Activity Task 란?
Task는 하나만 존재하는 것이
아니다.
일단 우리가 만든 Task는
Task Group 1에 해당한다.
Top Activity는 Task Stack의
가장 상위에 존재하는
Activity이며,
현재 Stack 기준으로 화면에
보여지고 있는 Activity이기도
하다.
Base Activity는 Task
Stack에 가장 하위에 있는
Activity이다.
이것을 Root Activity라고도
한다.
10. 1. Activity Task 란?
Task는 사용자의 입장에서 여러개의 패키지가 연동되어 실행되더라도
하나의 프로그램 처럼 보여지게 하기 위해 존재하는 것이다.
개발자의 입장에서는 하나의 패키지를 하나의 프로그램이라고 보면 된다.
본 개념은 사용자들을 위한 개념이기 때문이다.
11. 1. Activity Task 란?
Question) Task를 제거하려면 어떻게 해야할까?
A) Back Key(종료)등을 이용해서 "PackageA_3 -> PackageA_2 ->
PackageA_1 -> Launcher" 로 돌아가면 바로 Task는 사라지게 되는
것이다.
즉 Stack을 모두 비우면 된다.
Question) 하나의 Task는 어떻게 하면 만들어 질까?
Launcher에서 시작
된 패키지는 모두 새
로운 Task를 만들게
된다.
정답인가????
18. 2.1.2. <activity android:taskAffinity> 속성
askAffinity는 친화력이라고 해석하면 적당할 것 같다.
각각의 <activity>마다 taskAffinity라는 속성을 가진다.
이 속성의 값이 같을 경우 서로는 친화력이 있다고 볼 수 있는 것이다.
"adb shell dumpsys activity" 명령으로 확인해보면…
Hist 1,2,3 은
taskAffinity=com.test.PackageA
Hist 4는
taskAffinity=com.test.PackageB
안드로이드에서는 "taskAffinity"값을 입력하지 않으면,
기본적으로 해당 패키지 명으로 "taskAffinity"가 설정이 되기 때문이다.
"FLAG_ACTIVITY_NEW_TASK" Flag를 아무리 사용해도
활성화 하려는 Activity의 taskAffinity 값과
동일한 "taskAffinity" 값을 가지는 Task가 존재하는 경우
해당 Task 마지막에 연결되어 활성화 되는 것이다.
19. 2.1.2. <activity android:taskAffinity> 속성
Task1과 같이 Task 내에 다양한
taskAffinity 값을 가지는 Activity가
존재해도,
Task1의 taskAffinity는 Root에
해당한는 Activity의
taskAffinity가
바로 Task의 taskAffinity가 되는
것이다.
한 Task 내에
Root Activity가
Task를 대표하는
taskAffinity가 된다.
20. 2.1.2. <activity android:taskAffinity> 속성
어느 곳에서 새로운 Activity를 활성화하려고 한다.
새로운 Activity를 활성화 할때 Intent의
Flag를 "FLAG_ACTIVITY_NEW_TASK"라고
주었다. 그리고 해당 Activity의 taskAffinity는 "com.test.PackageC"이다.
과연 어떤 Task에 연결이 될까?
21. 2.1.2. <activity android:taskAffinity> 속성
Task3에 연결이 된다.
그 이유는 Task3의 대표 taskAffinity가 "com.test.PackageC"이고
활성화 되려는 Activity의 taskAffinity 또한 "com.test.PackageC"이기 때문이다.
잘 이해가 되었는가?
25. 2.1.3. FLAG_ACTIVITY_MULTIPLE_TASK
본 속성은 절대 독자적으로 사용할 수 없는 Flag이며,
독자적으로 사용한 경우 아무런 의미가 없다.
본 속성은 꼭 "FLAG_ACTIVITY_NEW_TASK"와 같이 사용되어야 한다.
"FLAG_ACTIVITY_NEW_TASK" Flag는
같은 taskAffinity 속성이 존재하는 Task가 있을 경우
새로운 Task를 생성하지 못하고 같은 이름의 Task Top으로 추가됨을 배웠다.
그렇다면 같은 taskAffinity Task가 존재하는 경우 새로운 Task를 만들 수
없을까?
본 속성을 "FLAG_ACTIVITY_NEW_TASK"와 같이
사용하면 무조건! 무조건 ! 무조건!
새로운 Task를 만들고 그 안에 Root로 해당 Activity가 활성화 된다.
31. 2.1.4.1 standard 값
이 속성은 별도의 Task를 만들지 않고 해당 Task에 계속 쌓여가는 것이다.
Default 라는 것은 일반적으로 가장 많이 사용된다고 볼 수 있는 것이다.
"FLAG_ACTIVITY_NEW_TASK" 속성과 "FLAG_ACTIVITY_MULTIPLE_TASK"
속성을 같이 사용하여 분명 Task를 분리하였다.
하지만 AndroidManifest.xml에 <activity launchMode> 값을 적어주지
않았으므로 "standard"가 아닌가?
방금 "standard"는 새로운 Task를 만들지 않고 기존 Task에 추가된다고 했다.
모순이 아닌가?
Task를 컨트롤하는 속성은 크게 두 가지가 있다.
하나는 AndroidManifest.xml에 <Activity> 속성과 또 하나는 Intent Flag이다.
즉 AndroidManifest.xml에 <Activity> 속성보다 Intent Flag가 우선순위가 높다는
것이다.
32. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
본 속성을 활성화 되려는 Activity에 설정하게 되면
활성화 될 Task의 Top에 같은 Activity가 존재할 경우,
새로운 Activity를 Top으로 올리지 않고 기존의 Top을 재 사용한다.
(이 것을 Instance를 생성하지 않고 기존 Instance를 재활용한다 라고
표현하기도 한다.)
예를 보자.
A Activity가 B Activity를 활성화하고
B Activity는 다시 자신 Activity를 다시 활성화 하고 이를 반복한다.
33. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
계속 B Activity Instance가 쌓이는 것을 볼 수 있다.
이 것은 일반적인 상황이다.
34. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
B Activity에 해당하는
AndroidManifest.xml에서 "android:launchMode="singleTop"을 추가하면…
35. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
B Activity를 계속 활성화 하여도 B Activity는 하나 이상 Instance를 생성하지 않
았다.
38. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
아까 예제에서, B를 재사용한다고 했다.
그러면, B는 이전에 배웠던 Activity 생명주기가 어떻게 될까?
B가 활성화 될때마다 onPause -> onResume만 반복한다.
즉 새로운 Activity의 Instance가 생성되는 것이 아니라,
단지 하나의 B Instance가 onPause -> onResume 생명주기만 반복하는
것을 알 수 있다.
이 것이 바로 기존 Instance의 재사용이라는 것이다.
그렇다면 재사용이라는 의미가 무엇인지 생각해 보아야 한다.
39. 2.1.4.2 singleTop 값 ( == Intent Flag FLAG_ACTIVITY_SINGLE_TOP)
!!! 해당 속성은 Intent Flag에서 "FLAG_ACTIVITY_SINGLE_TOP" 또한
완전히 동일한 기능을 가진다.
다른 점이라면 AndroidManifest.xml에서 launchMode="singleTop"이라고
미리 고정해서 사용하느냐
혹은
코드 상에서 startActivity()함수를 사용할 때 Intent Flag로
"FLAG_ACTIVITY_SINGLE_TOP" 라고 설정하느냐 차이 밖에 없다.
40. 2.1.4.3 singleTask 값
"singelTask"라고 AndroidManifest.xml의 <activity>에 설정하면
해당 Activity는 새로운 Task에서 생성이 된다.
즉 해당 Activity는 새로운 Task의 Root가 된다는 말이다.
예를 보자..
일반적으로 순차적으로 호출하는 예는 다음과 같다.
41. 2.1.4.3 singleTask 값
해당 패키지를 실행했을 때
Activity Stack은 아래와 같을 것이다.
A :
Intent intent = new Intent(this, B.class);
startActivity(intent);
B :
Intent intent = new Intent(this, C.class);
startActivity(intent);
C :
Intent intent = new Intent(this, D.class);
startActivity(intent);
42. 2.1.4.3 singleTask 값
자 Android Manifest.xml에 아래와 같이
이번에 설명하고자 하는 launchMode="singleTask"를
C Activity에 추가해 보자.
43. 2.1.4.3 singleTask 값
우리는 C Activity가 새로운 Task에서 실행이 되므로
아래와 같은 구조가 될 것이라고 생각할 것이다.
정말 그렇게 되었는지 Activity Stack을 확인해 보자.
이상하다!!! C Activity는 전혀 새로운
Task에 올라가지 않았고,
이전과 같다.
44. 2.1.4.3 singleTask 값
왜 그럴까?
이런 현상은 "FLAG_ACTIVITY_NEW_TASK"를 설명하면서 겪었던 문제이다.
그 원인은 바로 아래와 같은 이유 때문이다.
그렇다. taskAffinity가 같은 경우 아무리 새로운 Task에서 실행하려고 해도
원하는 결과가 나오지 않는다.
45. 2.1.4.3 singleTask 값
대부분 사람들은 "FLAG_ACTIVITY_NEW_TASK"에만 tastAffinity가 적용된다고
생각한다. 하지만 잘못된 생각이다.
자 그럼 taskAffinity로 인해서 그러한지 증명해 보자.
아래와 같이 C Activity에 taskAffinity값을 변경해 보자.
47. 2.1.4.3 singleTask 값
1번과 같이 테스트 패키지를 실행한다.
2번과 같이 활성화 되는 A는 singleTask로 설정되어 있다.
3,4번 과정을 통해 A -> B -> C 로 Activity Stack에 쌓였을 것이고
다시 해당 패키지를 5번과 같이 실행하면,
ActivityStack은 A -> B -> C 이므로 가장 Top Activity는 C임에도 불구하고 A로 간다.
48. 2.1.4.3 singleTask 값
이 것은 singleTask의 또 다른 아주 중요한 특성이다.
SingleTask로 구성된 Task는 Background 전환 후 다시 Foreground로 돌아 왔을 때,
SingleTask으로 설정된 Activity(Root Activity)만 남고 모두 제거 된다.
49. 2.1.4.3 singleTask 값
위에서 B,C는 제거되고 A가 다시 활성화 되었다고 했다.
그 말은 뒤에 있던 A가 앞으로 왔다는 것을 의미한다.
이렇게 A가 Front로 오게 되는 경우 A에게는 특정한 Intent Flag가 전달된다.
"FLAG_ACTIVITY_BROUGHT_TO_FRONT" Flag가 그것이다.
이 Flag는 시스템에 의해 셋팅된 Flag이며 뒤에 있던 Activity가
SingleTask 속성으로 앞으로 왔다는 것을 알리는 것이다.
보다 정확한 표현은 시스템에 의해 뒤에 있던 Activity가 앞으로 왔으므로
시스템에서 해당 Flag를 셋팅해서 앞으로 오게 된 Activity에게 그것을 알려 주는
것이다.
50. 2.1.4.4 singleInstance 값
해당 속성은 singleTask와 유사하게 새로운 Task를 생성하는 기능이다.
하지만 taskAffinity와 상관 없이 무조건 새로운 Task를 생성한다.
또한 새로 생성된 Task 내에는 "singleInstance"라고 설정된 Activity
하나만 존재하도록 한다.
해당 Activity 위로 다른 Activity가 올라가지 않는다는 말이며,
생성된 Task 내에는 "singleInstance"라고 설정된 Activity가
유일하다. (즉 Root Activity인 동시에 Top Activity이다.)
추가적으로 해당 속성은 "singleTop"과 유사한 점도 가진다.
하나의 Task내 하나의 Activity가 활성화 되지만,
해당 Activity를 중복해서 활성화 하더라도
계속 새로운 Task내 하나의 Activity가 계속 만들어 지는 것이 아니라,
기존에 새로운 Task내 하나의 Activity가 만들어 졌다면,
다시 해당 Activity를 활성화 하더라도 기존 생성된 Activity를 그대로 재사용한다는
점이다.
예를 보자…
52. 2.1.4.4 singleInstance 값
- "singleInstance"로 설정된
Activity는 무조건 별도의 Task를
새롭게 만들고 배치된다.
그렇다면
C Activity가 별도의 Task2에
존재한는 것을 이해할 것이다.
- 모두 동일한 taskAffinity임에도
불구하고 별도의 Task에서
C Activity가 실행이 되었다.
singleInstance는 taskAffinity의
속성과 상관없이 별도의 Task에서
해당 Activity가 활성화 된다.
- "singleInstance"로 만들어진 Task
내에는 무조건 하나의
Activity(Instance)만 존재한다.
그러므로 D Activity가 Task2번의
C Activity위에 올라가지 못하는
것을 이해 할 것이다.
D Activity는 새로운 Task에서
생성되는 아무런 Flag나
AndroidManifest.xml에 설정된
값이 없으므로 이 경우
taskAffinity가 동일한 곳의 Task에
붙게 되는 것이다.
55. 2.1.4.4 singleInstance 값
"singleInstance"의 경우 "singleTop"같은 특성도 가진다고 했다.
B Activity는 "singleInstance"로 설정 되었으므로,
B Activity가 활성화 될때는 꼭 새로운 Task에서 실행이
된다.
위의 과정은 A -> B -> B -> B ...과 같이
B Activity가 계속 활성화를 시도한다.
그러므로 이와 같은 Task 구조가 될 것이라고 생각할 수
있다.
하지만!!!
59. 2.2. Task Activity 정리하기
2.2.1. FLAG_ACTIVITY_NO_HISTORY
(== AndroidManifest.xml <activity andoird:noHistory>)
본 속성은 Activity Stack 내에 History를 남기지 않겠다는 속성이다.
우리는 특정 Activity의 경우 Backkey 등을 눌렀을때 다시
활성화 되는 것을 원치 않을 때가 있을 것이다.
예를 들어
Password 등을 묻는 Activity의 경우 최초 한번만 승인이 되고 그 다음
해당 application을 사용하기 원할 것이다.
예를 보자. 일반적인 A->B->C 인 상황이다.
61. 2.2. Task Activity 정리하기
2.2.1. FLAG_ACTIVITY_NO_HISTORY
(== AndroidManifest.xml <activity andoird:noHistory>)
이상하게도 B Activity가 그대
로 남아 있다.
1,2번을 보면 B Activity의
상태가 "FINISHING"인 것을
알 수 있다.
즉 B Activity는 이미 종료된
것이다. 즉 없는 것이나
마찬가지라는 것이다.
C Activity에서 BackKey를
눌러보면 B Activity가 다시
활성화 되지 않고
바로 A Activity가 활성화 될
것이다.
(여기서 한가지 더 알수 있는 것이 있다. 우리는 B -> C 를 활성화 할때,
분명 B Activity를 finish()함수를 사용해서 종료하지 않았지만 finish가 되었다.
그 이유는 noHistory속성을 주게 되면 해당 B가 Foreground에서 벗어나 Background가
되는 즉시 시스템에서 강제로 Finish를 시켜버리는 것이다.)
63. 2.2. Task Activity 정리하기
2.2.2. FLAG_ACTIVITY_CLEAR_TOP
해당 속성은 Task 내에 존재하는 특정 Activity부터 Top Activity까지 모두
제거한뒤 다시 그 특정 Activity를 활성화 시켜 Top이 되도록 한다.
이와 같이 Task내에 "B"가
존재할때,
"B“ 를
"FLAG_ACTIVITY_CLEAR_TO
P"
Intent Flag 속성을 주어
하나 더 추가하는 경우
1,2,3번과 같이 D,C,B Activity가
모두 제거되고,
다시 "B"가 추가되어
Top이 되도록 하는 속성이다.
64. 2.2. Task Activity 정리하기
2.2.2. FLAG_ACTIVITY_CLEAR_TOP
C->B를 호출할 경우에 "FLAG_ACTIVITY_CLEAR_TOP" 을 추가
65. 2.2. Task Activity 정리하기
2.2.2. FLAG_ACTIVITY_CLEAR_TOP
마지막 "B" Activity가
"FLAG_ACTIVITY_CLEAR_T
OP"
Intent 속성으로 활성화 될 때,
"B"와 "C"가 onDestroy 되고
"B"는 다시 onCreate 되는 것을
알 수 있다.
(생명주기에서 onDestroy가
호출된다는 것은 Task에서
Pop 즉 제거된다는 의미이다.)
66. 2.2. Task Activity 정리하기
2.2.2. FLAG_ACTIVITY_CLEAR_TOP
그렇다면 본 Flag는 어떤 경우에 사용될 수 있을까?
최초 회원 가입의 절차가 필요한 패키지의 예이다.
67. 2.2. Task Activity 정리하기
2.2.3. FLAG_ACTIVITY_REORDER_TO_FRONT
이 Flag는 Task에 존재하는 특정 Activity를 Top으로 옮길 수 있다.
아래의 그림을 통해 이해해 보자.
이미 Task내 활성화된
"B" Activity를 다시
활성화 할 때,
해당 속성을 주게 되면
아래에 실행되었던
"B" Activity가 Stack의
개념을 무시하고
최 상위 Top으로
이동하게 된다.
이동된 "B" Activity는
그대로 재사용 된다.
어쨌든 이 Flag가 유용한 경우도
있을 것이다.
하지만 Stack의 구조를 깨 버린다.
이는 많은 혼돈을 줄 수 있다.
68. 2.2. Task Activity 정리하기
2.2.4. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
이 둘은 밀접한 관계에 있다.
2.2.5. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
"FLAG_ACTIVITY_CL
EAR_WHEN_TASK_
RESET" intent
속성으로
쌓여진 Activity는 해당
Task가
background에서
foreground로 변할때,
"FLAG_ACTIVITY_R
ESET_TASK_IF_NEE
DED" intent 속성에
의해
Task에서 정리된다는
것이다.
69. 1번과 같이 "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET" Intent 속성으로
특정 Activity가 stack에 올라가고 2번과 같이 일반 Activity가 Stack에 올라 갔다.
해당 Flag부터 Stack에 쌓여진 Activity는 어떤 조건이 되면
Stack에서 제거 하겠다는 의미를 가진다.
(Stack에서 제거란 해당 Activity가 Destroy 되는 것을 의미한다.)
자 이제 그 조건만 이해하면 되는 것이다.
그 조건이란
1. 해당 Task가 Background가 되고 다시 Foreground가 된 경우
2. Foreground가 될때 특정 활성화 될 Activity의
Intent 속성이 "FLAG_ACTIVITY_RESET_TASK_IF_NEEDED" 으로 설정된
경우이다.
3,4,5번 과정이 위의 조건을 의미한다.
6번과 같이 해당 Activity가 제거됨을 의미한다.
2.2. Task Activity 정리하기
2.2.4. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
2.2.5. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
70. 2.2. Task Activity 정리하기
2.2.4. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
2.2.5. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3번에서 4번의 Activity를 활성화 할 때 "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET" 속성을 주고
5번 과정에서 home key에 의해 background로 전환된다.
7번 다른 패키지에서 다시 D Activity로 활성화 함으로써 foreground로 전환한다.
D Activity를 활성화 할 때는 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED와
FLAG_ACTIVITY_NEW_TASK를 줄 것이다.
예를 보자.
72. 2.2. Task Activity 정리하기
2.2.4. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
2.2.5. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3번과정에서 D를 활성화 하려고 하였으나 제거되었고
4번에서 그 이전 C를 활성화 하려고 하였으나 제거 되었다.
결국 "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET" 영향을
받지 않은 마지막 B가 활성화 된 것이다.
73. 2.2. Task Activity 정리하기
2.2.4. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
2.2.5. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
그렇다면 Task를 정리하는 "FLAG_ACTIVITY_RESET_TASK_IF_NEEDED" 는
어느 곳에서 사용되고 있을까? 그것은 바로 Launcher에서 늘 사용되고 있다.
위와 같은 과정을 ResetTaskTest 패키지의 "D" Activity를 활성화하는 패키지 없이
재현해 보자.
ResetTaskTest 패키지를 실행해서 동일하게 아래와 같이 실행하자.
Launcher에서는 설치된 모든 App를 실행할 수 있는 아이콘이 존재한다.
그 아이콘을 통해 실행된 모든 App의 Activity는
"FLAG_ACTIVITY_RESET_TASK_IF_NEEDED" 속성을
가진다. 즉 Task를 무조건 정리한다는 것이다.