-
아래 명령을 통해 activity stack 을 볼 수 있다.
$ adb shell dumpsys activity
여기서 TaskRecord 가 Task 의 group 구분이며,
이 안에 Hist #N 로 표기된 HistoryRecord 부분을 보면 그 안에 쌓인 Stack 을 볼 수 있다.
stack 은 packageName/Activity 형태로 표기된다.
-
FLAG_ACTIVITY_NEW_TASK 는 affinity 가 같은 task 위에 쌓이게 된다.
따라서 A affinity 를 가진 A1 Activity 에서 A2 Activity 를 해당 flag 와 함께 띄워도 A stack 에 쌓인다.
-
taskAffinity 의 기본값은 packageName 이다.
-
taskAffinity 가 같은 Activity 들을 따로 띄우려면..
FLAG_ACTIVITY_MULTIPLE_TASK 를 적용하면 된다.
(권장되지는 않는다.)
-
launchMode 의 standard 값은 ActivityInfo.LAUNCH_MULTIPLE 과 같다.
이는 default launchMode 값이다.
-
Manifest 의 Activity 속성보다 Intent flag 의 우선순위가 높다.
-
launchMode 의 singleTop 은 FLAG_ACTIVITY_SINGLE_TOP 과 같다.
A 가 다시 A 를 띄울 때 A 가 새로 생기지 않고 onNewIntent 가 불린다.
이 때 onPause, onNewIntent, onResume 로 불린다.
-
여기에 tricky 함에 또 하나 있는데..
FLAG_ACTIVITY_CLEAR_TOP flag 를 사용할 경우 2가지 케이스로 Activity 동작이 분기한다.
1. singleTop 으로 정의되거나 FLAG_ACTIVITY_SINGLE_TOP 도 flag setting 한 경우에는..
해당 Activity 가 onNewIntent 가 불리며 그 위의 activity 를 clear 한다.
2. multiple (default) 인 경우에는..
해당 Activity 를 포함해서 clear 시킨 후에, 해당 Activity 를 relaunch 시킨다.
-
launchMode 의 singleTask 는 가장 까리한 항목이다.
instance 자체는 1개를 유지하지만, 같은 affinity 를 가진것 위에는 올라갈 수 있다.
그리고 그 위에 같은 affinity 를 가지지 않은 것도 쌓을 수도 있다.
따라서 singleTask 를 새로운 task 에서 띄우려면 affinity 를 unique 하게 지정해야 한다. (FLAG_ACTIVITY_NEW_TASK 없이도 된다.)
-
singleTask 에는 또 하나의 중요한 특성이 있는데..
이 녀석이 root 로 있는 task 는 bg -> fg 로 돌아오면, root 만 남고 모두 제거된다. (root 일때만 valid)
이는 FLAG_ACTIVITY_BROUGHT_TO_FRONT 가 작동하기 때문이다.
-
singleTask 는 single instance 를 보장하기 때문에
A1 -> A2(singleTask) -> A3 -> A2 로 intent 를 호출한 경우
A3 는 종료되면서 A2 가 올라오고, onNewIntent -> onRestart -> onStart -> onResume 의 순서로 재개된다.
A1 -> A2(singleTask) -> A2 의 경우 singleTop 과 같이
onPause -> onNewIntent -> onResume 을 타게 된다.
결론적으로만 보면 singleTask 의 launch 는 FLAG_ACTIVITY_SINGLE_TOP | FLAG_ACTIVITY_CLEAR_TOP 이라고 보면 된다.
-
singleInstance 는 singleTask 와 비슷하게 single instance 를 지원하면서, task 에 유일하다는 추가적 특성도 갖는다.
항상 root 에 있으며, 그 위에 다른 activity 도 올라가지 않는다.
또한 single instance 이기 때문에 재사용이 된다. (singleTask 와 같은 life cycle 코드를 탄다.)
따라서 이 녀석이 실행시키는 모든 activity 는 사실 자체적으로 FLAG_ACTIVITY_NEW_TASK 를 갖는 것과 같다.
-
FLAG_ACTIVITY_NO_HISTORY 는 해당 Activity 라 bg 상태가 되면 자동으로 finish 가 된다.
-
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 은 오묘한 녀석이다.
이 녀석을 set 한 Activity 부터 그 위로 stack 된 녀석은 어떤 조건이 되면 함께 제거된다.
그 조건은.. 해당 task 가 bg -> fg 가 될 때 활성화 될 activity 의 intent 속성에FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 가 설정된 경우이다. (이 경우 요청된 Activity 가 안 뜰 수 있다.)
많은 launcher 가 앱을 실행시킬 때 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag 를 추가한다.
이에 따라 bg -> fg 가 되었을 때 자동으로 RESET 되기도 한다.
-
alwaysRetainTaskState 값은 ICS 부터 deprecate 되었다. (실제 동작하지 않는다.)
-
clearOnBackground=true 속성을 주면, bg 가 되는 순간 root 를 제외하고 모두 제거된다. 이는 root activity 에 설정한다.
finishOnTaskLaunch=true 가 되면 bg 가 되는 순간 설정된 Activity 만 제거 대상이 된다. 이는 root activity 에는 설정할 수 없다.
-
allowTaskReparenting 은 원래의 부모가 해당 task 의 activity 를 가지고 온다는 이야기이다.
여기서 주의할 것은!!!!
실행 시점에 바로 해당 activity 를 띄운 task 의 stack 으로 쌓이는 것이 아니라 같은 affinity task 가 fg 로 올라올때, 다른 task 에 있던 같은 affinity 를 가진 녀석들이 이사오는 것이다.
또한 무조건 이사오는 것이 아니라, FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 속성으로 fg 가 되어야만 이사를 온다.
A1, A2 는 allowTaskReparenting = true 이다.
-
1번 실험
(누군가의 test 결과 참조)
(POS 실제 실험 결과)
A0
B0 -> A1 -> A2
A앱이 fg 되어도 stack 을 유지한다.
이 상태에서 B앱을 수행시키면..
A0
B0
A1 -> A2
Launcher 에서 A 앱을 수행시키면 A0 로 이동한다.
A앱을 Recent app 에서 죽인 다음 A 앱을 다시 수행하면 A2 로 이동한다...
정리
1. 버전에 따라 다른가보다...
2. 오히려 최신 버전에서 reparenting 되어야 할 것 같은 상황에서 안 되고 있고,
B앱을 실행할 때 A1 -> A2 가 A0 에 붙는게 아니라 다른 task 로 분리된다.
-
2번 실험
(누군가의 test 결과 참조)
allowTaskReparenting 관련..
여기서 한가지 더 주의해 볼 것은!!!
B0 -> A1 -> A2
상태에서 B앱을 bg -> fg 로 하면 아래와 같이 된다. (이 역시 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 속성으로 실행시켰을 때이다. 대부분의 launcher 가 해당 flag 를 주고 띄운다.)
A1 -> A2
B0
그럼 이 상태에서 A 앱을 실행시키면..? A1 이 뜬다... (왜...인거죠..? 최소한 A0 도 아니고... A2 도 아니고... )
(POS 실제 test 결과)
실험 결과는 같으며, A2 앱이 뜬다. ( 기대 동작이라 다행이다. )
결론 : A앱이 떠 있지 않은 상태에서 B앱을 다시 실행시켰을 때만 reparenting 이 정상동작한다.
-
실험 3
(누군가의 test 결과 참조)
(POS 실제 test 결과)
B0 -> A1 -> A2
A0
이 상태에서 B앱을 다시 실행시키면 실험1 과 같은 결과가 된다.
B0
A0
A1 -> A2
-
최종 결론
1. 버전에 따라 동작이 다른 것으로 보인다.
2. POS 기준으로는 reparenting 은 B앱이 reparenting 속성을 가진 A앱의 Activity 들을 launch 했으며, FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag 와 함께 B앱이 다시 실행될 때, A앱과는 별개로 별도의 task 로 존재하게 된다. ( A앱의 실행이 reparenting 을 초래하지 않는다. )
따라서 B앱에서 A 의 Activity 들이 분리될 때 A 의 task 가 있다면 이 녀석이 A앱의 main 이 되고, 그렇지 않으면 분리된 녀석들이 A의 main 이 된다.
-
끝!!!
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] dpi 값이 바뀔 수 있구나?!! ㄷㄷㄷ (0) | 2020.08.15 |
---|---|
[android] 앱 업데이트시 다운로드 사이즈 줄이기 (0) | 2020.08.14 |
[android] javax.net.ssl.SSLPeerUnverifiedException: No peer certificate (0) | 2020.08.11 |
[android] Android Studio 의 Tip & Tricks (0) | 2020.08.04 |
[android] Custom Text Selection Actions (0) | 2020.08.03 |
댓글