안녕하세요

프로그램 과정에서 막혔던 문제들에 대한 해결책 정리


페이지 목록

2011년 1월 17일 월요일

[안드로이드] 인텐트 flag를 통한 Activity flow 제어(android activity flow control by intent flag)

인텐트에는 4가지의 flag가 존재한다.


No flag를 포함하면 다섯가지


이 flag들을 통해서 android의 activity stack을 control 할 수 있다.


안드로이드로 개발을 하다보면 뜻하지 않게 엄청난 양의 Activity들이 쌓여나가는 것을 볼 수 있다. 현재 필자가 개발하고 있는 프로그램에서는 GirdView에 image들을 띄우고 그 중 하나의 image를 선택하여 배경화면으로 세팅하는 것이 있다.

이 때 다음과 같은 일이 발생한다.

GridView가 있는 Activity -> GridView에서 선택한 Image를 확대해서 보여주는 Activity -> (확인 클릭 시) GridView가 있는 Activity 로 다시 이동 -> GridView가 있는 Activity에서 다른 Image 선택 -> Image 확대 Activity -> GridView가 있는 Activity -> 확대 된 image가 있는 Activity


이렇게 몇 번 GridView에서 이미지를 선택해주면 엄청난 양의 Activity들이 쌓이는 것을 볼 수있다. 이를 제어하기 위해 인텐트에 플래그를 적용시켜 주는 것이다.


먼저 FLAG_ACTIVITY_SINGLE_TOP 입니다. 우선 간단하게 그림으로 표현해 보았습니다. A 와 B 두 가지 Activity 가 있는 데, A 라는 Activity 는 B 를 B 라는 Activity 는 다시 자기 자신인 B 를 호출 하는 경우라고 가정해 보겠습니다.

호출하는 Activity B 가 이미 Task 의 가장 앞에 위치하는 경우, 또 하나의 B 를 생성하는 대신, 기존에 존재하는 B Activity 가 재활용됩니다. 이 때 B 가 재활용된다는 것을 개발자가 알아채고 새롭게 전달되는 Intent 를 사용할 수 있도록 B Activity 의 onPause() / onNewIntent() / onResume() 가 순차적으로 호출됩니다. 별 생각없이 동일한 Activity 를 여러번 생성하는 것은 메모리 사용량과 Activity 시작 속도 양쪽 모두에 악영향을 끼칠 수 있습니다. (특히 이미지가 덕지덕지 붙어 있는 Activity 라면). 이런 경우 FLAG_ACTIVITY_SINGLE_TOP 를 적절하게 활용하면 제법 큰 효과를 볼 수 있습니다.


두 번째는, FLAG_ACTIVITY_NO_HISTORY 플래그입니다. 우 선 간단하게 그림으로 표현해 보았습니다. A 와 B 두 가지 Activity 가 있는 데, A 라는 Activity 는 B 를 B 라는 Activity 는 A 를 호출한 후 에 (A->B->A) 사용자가 Back 키를 누르는 경우를 가정해 보겠습니다.


말 그대로, FLAG_ACTIVITY_NO_HISTORY 로 설정된 Intent 로 시작된 Activity B 는 Task 에 그 흔적을 남기지 않게 됩니다. B 에서 또다른 A 를 시작한 후, Back 을 누르면 일반적인 경우 이전에 실행되었던 B 가 나타나지만, NO_HISTORY 를 사용하는 경우 맨 처음에 실행 되었던 A 가 화면에 표시됩니다. 몇 가지 주의할 점이 있습니다. 우선 NO_HISTORY 를 사용하게 되면 Task 에 해당 Intent 의 정보가 기록되지 않기 때문에, A->B 인 상황 (그림에서 두 번째 단계...) 에서 홈키등을 눌러 다른 Task 로 전환된 후, 다시 본 Task 로 돌아오게 되면, A Activity 가 화면에 표시됩니다. 또한, B Activity 의 onDestroy() 가 호출되는 시점이 조금 애매합니다.일반적인 예상과는 달리, B 에서 또다른 A Activity 를 호출하는 세 번째 단계에서는 onStop 까지만 호출되고, 이 후에 새롭게 호출된 A Activity 가 사라지는 순간 (네 번째 단계) 에서야 onDestroy() 가 호출 됩니다.

FLAG_ACTIVITY_NO_HISTORY 는 여러가지로 쓸모가 있는데, 특히 특정한 이벤트에 대한 알람등을 위해 다이얼로그 형태로 화면에 표시되는 Activity 들에적용하기에 편리합니다. (대게의 경우 팝업은 해당 시점에 한번만 보여주면 되니까.)

다음으로 굉장히 유용한 플래그 두 가지를 동시에 설명해보고자 합니다. FLAG_ACTIVITY_REORDER_TO_FRONT 와 FLAG_ACTIVITY_CLEAR_TOP 플래그입니다. 우선 간략하게 그림으로 살펴 보겠습니다. A Activity 에서 B Activity 를 그리고 B 에서 A 를 호출하는 상황을 가정해보았습니다. (A->B->A)

FLAG_ACTIVITY_REORDER_TO_FRONT 는 매우 특이하게도 Task 의 순서 자체를 뒤바꿔 줍니다. 이 플래그를 사용하면, 런치하고자 하는 Activity 가 이미 Task 상에 존재하는 경우 해당 Activity 를 새롭게 생성하는 대신, 아래쪽에 위치한 Activity 의 순서를 Task 의 가장 위로 끌어올려줍니다. 따라서 A->B->A 의 순서로 Activity 호출이 일어날때, 새로운 A 가 생성되는 대신 아래쪽에 위치한 A 가 위로 올라와 최종적으로 B->A 의 형태로 Task 가 구성되게 됩니다. 어떤 Activity 에서 특정 Activity 로 점프하는 형식의 Flow 를 구성해야하는 경우 요긴하게 사용될 수도 있지만, Task 의 순서를 뒤섞는 다는 점에서 사용에 주의를 기울일 필요가 있습니다. (별 생각없이 남발하게 되면 Back 키가를 누를 때 엉뚱한 Activity 가 표시되어 사용자들이 굉장히 혼란스러워 하는 경우가 있습니다.)

마지막으로 소개해 드릴 플래그는 바로 FLAG_ACTIVITY_CLEAR_TOP 입니다. 제가 개인적으로 가장 사랑스럽게 생각하는 녀석입니다. 이 플래그가 사용되는 경우 런치하고자 하는 Activity 가 이미 Task 상에 존재하는 경우, 해당 Activity 위에 존재하는 다른 Activity 를 모두 종료시켜 줍니다. 따라서 A->B->A 로 호출이 일어나는 경우, B Activity 가 종료 되고, A Activity 만 Task 에 남게 됩니다. (A->B->C->A 인 경우에도 마찬가지로 B와 C 가 종료되고 A 만 남게 됩니다.)

이 Flag 는 특정 어플리케이션의 대쉬보드 (혹은 홈) Activity 를 호출할 때 굉장히 유용하게 사용될 수 있습니다. 즉 하나의 어플리케이션이 하나 혹은 두 가지의 주요한 Activity 와 그 외 특정 값을 선택하는등 단순한 일을 수행하기 위한 여러 개의 Sub-Activity 로 구성되어 있다면, 주요 Activity 를 호출하는데 이 Flag 를 사용함으로서 어플리케이션의 홈버튼등을 손쉽게 구현할 수 있습니다. 또 이 Flag 는 FLAG_ACTIVITY_REORDER_TO_FRONT 와는 달린 Task 의 순서를 뒤섞지 않음으로 사용자에게도 큰 혼란을 주지 않습니다. (사용을 적극 권장합니다.)

한 가지 주의해야할 점은 A->B->A 형태로 Activity 를 호출 하고자 할 때, 단순히 FLAG_ACTIVITY_CLEAR_TOP 만을 사용하게 되면, 기존에 생성되었던 A Activity 가 종료된 후 (onDestroy() 가 호출됨) 새롭게 A 가 생성 (onCreate()) 됩니다. 만일 기존에 사용된 A Activity 가 계속 사용되기를 원한다면, SINGLE_TOP 플래그와 함께 사용해야 합니다.

FLAG_ACTIVITY_SINGLE_TOP

Activity가 스택의 맨 위에 존재 하는 경우에 기존 Activity를 재활용 한다.

(Activity호출순서) 0->1->2->3 이렇게 스택이 쌓인 경우(스택의 맨 위는 3)

view plaincopy to clipboardprint?
intent = new Intent(this, Activity3.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

0->1->2->3 그래도 유지 된다. 대신 Activity3는 onPause()->onNewIntent() -> onResume() 호출된다.

3번 액티비티가 존재하지 않거나 스택의 맨 위가 아닌 경우 그냥 스택에 쌓이게 되며 onNewIntent() 도 호출된다.

FLAG_ACTIVITY_NO_HISTORY

해당 플래그를 주고 액티비티를 호출하면 호출된 액티비티는 스택에 남지 않는다.

0->1->2->3 호출할때 Activity2 에서 Activity 3를 호출할때

view plaincopy to clipboardprint?
intent = new Intent(this, ActivityTest3.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);

하면 스택에는 0->1->3 만 남게 된다. 하지만 Activity 2의 Destory()의 시점은 Activity 3이 종료 된 이후에 호출된다라는것을 주의한다.

FLAG_ACTIVITY_REORDER_TO_FRONT

스택의 순서를 변경해 준다.

0->1->2->3 일때 Activity 3에서 Activity 1을 호출 할때 이 플래그를 설정하면

0->2->3->1 로 변경된다. (안드로이드 문서에서 FLAG_ACTIVITY_CLEAR_TOP플래그를 무시한다고 되어 있다.)

FLAG_ACTIVITY_CLEAR_TOP

스택에 기존에 사용하던 Activity가 있다면 그 위의 스택을 전부 제거해 주고 호출한다.

0->1->2->3 일때 Activity 3에서 Activity 1을 호출할때 이 플래그를 설정하면

0->1 만 남게 된다. (2, 3은 제거) 이때 Activity 1은 onDestory() -> onCreate()가 호출된다. 삭제하고 다시 만들게 된다.

그래서~~ FLAG_ACTIVITY_SINGLE_TOP와 같이 써준다. 그러면 onNewIntent()-> onResume() 가 호출된다.

만약 스택에 없다면~~ 당연히 아무것도 지우지 못하고 맨 위에 올라가게 된다.

view plaincopy to clipboardprint?

intent = new Intent(this, ActivityTest1.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

[출처] [안드로이드] Intent Flag|작성자 늘순수하게

위 사이트에 들어가면 미처 스크랩 해 오지 못한 이미지들을 볼 수 있다. 이 이미지들이 플래그의 기능을 이해하는 데 도움을 줄 것입니다.

댓글 없음:

댓글 쓰기