본문 바로가기

Android/Tech

자주 쓰는 Intent Flag

Intent Flag

4대 컴포넌트 (Activity, Service, Broadcast, ContentResolver) 간 통신을 하려면 Intent 를 사용하여야 합니다.

안드로이드 앱 개발시 가장 빈번히 사용되는 경우는 단연 Activity 간 이동입니다.

이 Activity 들은 Task 라는 Stack 에 적재되며, 기기의 백 버튼을 누르면 pop() 됩니다. 즉, 화면에 보이는 Activity 는 삭제되고, 직전의 요소가 화면에 나타납니다

 

Task 에 적재되는 Activities 를 관리하는 것 역시 개발자의 몫이며(물론 시간이 오래 지나도록 사용하지 않는 Activity 는 OS 차원에서 제거해주기도 합니다.) 관리를 해야하는 이유는 당연히 Memory leak 에 대한 위험입니다.

 

개발을 하다보면 자주 사용하는 Flag 는

FLAG.ACTIVITY_CLEAR_TASK,

FLAG.ACTIVITY_NEW_TASK,

FLAG.ACTIVITY_CLEAR_TOP,

FLAG.ACTIVITY_NO_HISTORY

정도입니다.

 

자주 쓰는 만큼, 확실히 알아야 한다고 생각해서 직접 예제를 구현하여 테스트해보고, 그 결과를 기록하고자 합니다.

 


앱을 실행하면, Activity A - B - C - D - E 순서로 Task 에 쌓이도록 구현하였습니다.

(Activity 이름은 가독성을 위해 알파벳으로 구성하였습니다)

이를 그림으로 표현하면 다음과 같습니다.

 


1. FLAG.ACTIVITY_CLEAR_TASK & FLAG.ACTIVITY_NEW_TASK

 

CLEAR_TASK 과 NEW_TASK 는 꼭 같이 쓰여야 합니다. 따로 쓰면 아무런 효과도 없습니다.

Task 를 새로 생성하면서, 진행하고자 하는 Activity 만 Task 에 적재합니다.

본 예제에서는, Activity E 에서 Activity C 로 전환하면서, 해당 Intent 에 두 가지 flag 를 부여하였습니다.

진행하고 Task 를 살펴보면, 다른 Activities 는 삭제되고 Activity C 만 남습니다.


2. FLAG.ACTIVITY_CLEAR_TOP

 

목표 Activity 가 기존의 Task 에 적재되어 있다면, 해당 Activity 를 최상위로 두고,

목표 Activity 보다 상위에 적재되어있던 Activities 는 삭제합니다.

라고 알려져 있습니다.

 

그림으로 보면 다음과 같을 겁니다.

그림1.

그러나, 실제로 구현하고 살펴보니 조금 달랐습니다. 

위와 같은 설명 및 그림에 따르면, Activity C 로 돌아갔을 때 Activity C 의 구성이 남아 있어야 하지 않을까요?

 

그렇다면?

adb 를 통해 살펴봅니다. 그림 1은 Intent 전, 2는 후입니다. 

그림1
그림2

 

Activity C 의 해시값이 다름을 확인할 수 있습니다.

그림으로 표현하자면 다음과 같습니다.

 

그림 1 처럼 사용하고 싶다면, FLAG_ACTIVITY_SINGLE_TOP 을 함께 쓰면 됩니다.


3. FLAG.ACTIVITY_NO_HISTORY

 

이름 그대로, 기록을 남기지 않는다. 코드로 설명합니다.

 

binding.btnGoActivityB.setOnClickListener {
    startActivity(Intent(this@A, B::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NO_HISTORY
    })
}

btn_go_activity_b 를 누르면 Activity A 에서 Activity B 로 넘어갑니다. (당연히, Activity B 에서는 Activity C 로 넘어갑니다.)

그렇게 수행하면, 결과는 다음과 같습니다.

B 는 Task 에 남지 않는다.

1회성으로 Activity 를 사용하는 경우에 적합하겠습니다.


Extra. finish()

 

Splash 및 Intro Activity 를 구현하고 각종 flag 를 추가하여 HomeActivity 로 진행하는 경우가 많습니다.

그럴 땐, 그냥 삭제하고자 하는 Activity 에서 finish() 를 호출하자. 다음과 같이 말입니다.

 

lifecycleScope.launch { 
    delay(1500L)
    startActivity(Intent(this@IntroActivity, MainActivity::class.java))
    finish()
}

1.5 초 대기하고 MainActivity 로 전환합니다. 이후 finish() 를 호출하여 IntroActivity 를 메모리에서 해제합니다.

Activity C 에서 Activity D 로 이동할 때, finish() 메소드를 호출한 결과.

 


Extra2. 동일한 Activity 호출.

 

Activity E 에서 Activity E 를 호출하면 어떻게 될까요?

간단하다. E 위에 새로운 E 가 생깁니다. 다른 Activity 를 호출해도 마찬가지 입니다. 별다른 처리를 하지 않으면 새로운 Activity Instance 가 생성되어 새로이 적재됩니다.

 

 


확실히 알고 넘어가고 싶었습니다. 

 

사실 해당 내용과 관련된 글은 인터넷에 굉~장히 많습니다. 

 

정말 열 번 이상 본 것 같네요.

 

그러나 백견이 불여일타. 한 번 직접 쳐보니 훨씬 잘 이해되고, 기억이 선명하게 남습니다.