Android Developer

[Android] Task 와 Back Stack

졸려질려 2019. 7. 15. 17:37
반응형
Android_Activity_Back_Stack.md

[ActivityBackStack]

Task

  • 특정 작업을 수행할 때 사용자와 상호작용하는 액티비티들의 모음

  • 액티비티들은 실행된 순서대로 스택에 쌓인다. 이 스택을 백스택 이라고 한다.

    • Example - 새 메시지의 목록을 보여주는 액티비티 하나를 가지는 이메일 앱
      1. 사용자가 메시지를 선택하면 해당 메시지를 보여주는 새 액티비티가 실행되고 백스택에 PUSH 된다.
      2. 사용자가 뒤로가기 버튼을 누르면 방금 열린 액티비티가 종료되고 스택에서 POP 된다.
  • 다중 창 지원 환경(7.0 이상) 에서 어플리케이션들이 동시에 실행될 때, 시스템이 각 창마다 task들을 분리하여 관리 한다. 각 창은 여러 태스크를 가질 수 있다. (Chromebooks 에서 실행되는 안드로이드 앱의 경우도 마찬가지이다)

  • 기기의 홈 화면은 대부분의 Task 들이 시작되는 곳이다. 사용자가 앱 런처에서 아이콘을 터치하면 해당 앱의 Task 가 Foreground 로 온다. 만약 앱의 Task가 이미 존재하지 않는다면, 새로운 Task 가 생성되고 해당 앱의 main activity 가 새로운 스택의 root activity 가 된다.

Back Stack Process

  1. 현재 액티비티가 또 다른 액티비티를 실행할 때, 새로 실행된 액티비티는 스택의 top에 PUSH 되고 집중 받는다.
  2. 이전의 액티비티는 스택에 유지되지만 실행이 멈춰진다.(Stop) 이 때, 시스템은 멈춰진 액티비티의 현재 UI 상태를 저장해둔다.
  3. 유저가 Back 버튼을 누르면 현재 액티비티는 스택의 top 에서 POP 된다.(Destroy) 그리고 직전의 액티비티가 멈출 때 저장한 UI 상태를 불러와서 다시 실행된다.(Resume)
  • 스택에 있는 액티비티들은 절대 재배열 되지 않는다. 오직 스택에서 PUSH, POP 만 발생한다.

Background, Foreground

  • Cohesive Task
    • 사용자가 새 Task를 시작하거나 홈 버튼을 통해 홈 화면으로 갈 때 Task는 백그라운드로 이동 한다.
    • 백그라운드에 있는 동안 Task 내 모든 액티비티들은 BackStack 을 유지한채 멈춘다.

Example - Task A 의 백스택에 세 개의 액티비티가 있다. 1. 사용자가 홈버튼을 누르고 앱 런처에서 새 앱을 실행시킨다. 홈 버튼으로 인해 홈화면이 나타날 때, Task A 는 백그라운드로 이동한다. 2. 새 앱이 실행되면 시스템은 해당 앱을 위한 Task B를 생성하고 해당 앱의 액티비티들을 스택에 쌓는다. 3. 사용자가 새 앱을 어느정도 사용하다가 홈 버튼을 누르고 기존에 생성했던 Task A 를 위한 앱을 다시 실행시킨다. Task A 는 다시 포그라운드로 이동되며 이전에 사용했던 그대로 다시 실행된다. 4. 이 시점에서 사용자는 홈으로 이동하여 해당 작업을 시작한 앱 아이콘을 선택하거나 최근 화면에서 앱의 작업을 선택하여 작업 B로 다시 전환 할 수 있다. (Android MultiTasking)

Note : 백그라운드에는 여러 개의 Task 가 존재 할 수 있다. 하지만 동시에 많은 백그라운드 태스크를 실행시키면, 시스템은 메모리를 복구하기 위해 백그라운드 액티비티들을 파괴하기 시작한다.

Activity 와 Task 의 기본 동작

  • 백스택에 있는 액티비티들은 절대 재배열 되지 않는다. 만약 사용자가 앱을 실행하여 여러 액티비티 중 특정 액티비티를 실행시키게 되면, 지정된 액티비티의 인스턴스가 새로이 생성되고 스택으로 PUSH 된다 (해당 액티비티의 이전 인스턴스를 TOP 으로 가져오기 보다는).
  • 따라서 위 그림에서 볼 수 있듯이, 앱에 존재하는 하나의 액티비티는 여러번 인스턴스화 될 수 있다 (심지어 다른 Task 상에서).
  • 만약 사용자가 Back 버튼을 사용하여 뒤로 탐색한다면, 실행됐던 순서대로 액티비티의 인스턴스가 드러나게 된다.
  • 우리가 원한다면 이러한 동작들을 액티비티가 한 번만 인스턴스 되도록 바꿀 수 있다. 이 점은 뒤에서 쓰여질 Task 관리 에서 다뤄진다.
  • Activity 와 Task 의 기본 동작을 요약하면 다음과 같다.
    • Activiy A 가 Activity B 를 실행시킬 때, Activity A 는 Stop 된다. 하지만 시스템은 Activity A 의 현 상태(스크롤 위치, 입력된 텍스트 등등) 를 유지 한다. 만약 사용자가 Activity B 를 사용하다가 Back 버튼을 누르면, Activity A 는 Resume 되고 유지된 상태가 복구된다.
    • 사용자가 Home 버튼을 눌러서 Task 를 떠나게 되면, 당시 Activity 는 Stop 되고 Task 는 Background 로 옮겨진다. 시스템은 해당 Task 의 모든 Activity 상태를 유지 한다. 이후에 사용자가 해당 Task 를 불러오는 앱을 실행시키면 Task 는 Foreground 로 돌아오고 스택의 TOP 에 있는 Activity 는 Resume 된다.

Task 관리

  • 위에서 설명했던 Task 의 기본 동작을 원하는 대로 바꿀 수 있다.
    • < activity > manifest 성분의 attribute

      • taskAffinity
      • launchMode
      • allowTaskReparenting
      • clearTaskOnLaunch
      • alwaysRetainTaskState
      • finishOnTaskLaunch
    • startActivity() 를 이용한 intent 의 flag

      • FLAG_ACTIVITY_NEW_TASK
      • FLAG_ACTIVITY_CLEAR_TOP
      • FLAG_ACTIVITY_SINGLE_TOP

Caution : 대부분의 앱이 Activity 와 Task 의 기본 동작을 방해하면 안된다. 만약 특정 Activity 가 기본 동작을 수정 하도록 만들고 싶다면, 주의를 기울여서 실행 시킬 때나 다른 Activity 나 Task 에서 뒤로 돌아갈 때 특정 Activity 가 잘 동작하는지 확실히 테스트 해야 한다.

Launch Mode

  • Launch Mode 는 개발자가 Activity 의 새 인스턴스를 Task 와 어떻게 결합시킬 지 정의하는 속성이다.
  • Launch Mode 를 설정하는 방법은 두 가지 가 있다.
    • manifest file
      • manifest file 에서 activity 를 선언 할 때, 해당 activity 가 시작될 때 Task 에 결합되는 방식을 지정할 수 있다.
    • Intent flags
      • startActivity() 메서드를 호출 할 때, Intent 안에 flag 값을 설정하여 Activity 의 Launch Mode 를 설정 할 수 있다.

Note : manifest 파일에서 사용 가능한 일부 Launch Mode 는 Intent 의 flag 로 사용 할 수 없다. 반대로 flag 로써 사용 가능한 일부 Launch Mode 가 manifest 파일에서 선언 될 수 없다.

Manifest file

  • manifest file 에서 Activity 를 선언 할 때, <activity>launchMode 사용하여 Activity 가 Task 와 결합되는 방식을 지정할 수 있다.
  • launchMode 속성에는 총 4가지 속성이 존재한다. ( 추가 내용 : https://choboit.tistory.com/24 )
    • standard
      • Default
      • Activity 가 실행될 때마다 새 인스턴스 를 생성한다.
    • singleTop
      • 실행시킨 Activity 의 인스턴스가 현재 Task 의 TOP 에 이미 존재할 경우, onNewIntent() 메서드를 통해 기존의 Activity 로 intent 를 라우팅한다.
    • singleTask
      • 새로운 Task 를 생성하고 새 Task 에서 root Activity 로 인스턴스화 한다.
      • 하지만 다른 Task 에서 해당 Activity 가 이미 존재 한다면 onNewIntent() 메서드를 통해 기존의 Activity 로 intent 를 라우팅한다.
      • 각 Activity 의 인스턴스는 한 번에 한 개만 존재 할 수 있다.
    • singleInstance
      • 하나의 Task 에는 오직 하나의 Activity 인스턴스만 존재한다.

Scenario : singleTask 로 launchMode 가 설정된 브라우저 앱 1. 안드로이드 브라우저 앱은 웹 브라우저 Activity 가 항상 자체 Task 에서 열리도록 선언한다( <activity> 요소에 singleTask launch mode 로 설정함). 2. 사용자의 앱이 안드로이드 브라우저를 열기 위해 intent 를 발생시키면, 해당 액티비티는 사용자 앱의 Task 내에 위치하지 않는다. 3. 브라우저를 위한 새 Task 를 만들거나 만약 이미 background 에 존재한다면 기존의 Task 를 foreground 로 가져오고 새 intent 값을 전달한다. 4. Back 버튼은 항상 사용자에게 이전의 Activity 를 보여주게 한다. 그런데 만약 singleTask 로 설정한 Activity 를 시작했을 때 해당 Activity 가 background 에 이미 존재하다면 해당 Activity 가 포함되어 있는 Task 통째로 foreground 로 가져와진다. 5. 이 때 백스택은 방금 가져온 Task 의 모든 Activity 를 백스택의 TOP 에 포함시킨다.

  • manifest 에서 설정하는 launchMode 사용에 관련된 더 많은 정보를 얻고 싶다면, <activity> 문서를 참고한다. 해당 문서에는 launchMode 속성과 허용 가능한 값들이 더 자세히 나타나있다.

Intent flags

  • startActivity() 로 전달되는 Intent 의 flag 값을 통해 Activity 가 Task 와 결합되는 기본 방식을 변경 할 수 있다.
  • flag 값은 총 3 가지가 존재하다.
    • FLAG_ACTIVITY_NEW_TASK
      • singleTask 와 같이 동작한다.
      • 새 Task 에 Activity 를 시작한다. 만약 Task 가 이미 존재한다면 Task 는 이전의 상태를 복구하여 foreground 로 돌아오고 해당 Activity 는 onNewIntent() 메서드로 새 Intent 값을 받는다.
    • FLAG_ACTIVITY_SINGLE_TOP
      • singleTop 과 같이 동작한다.
      • 실행되려는 Activity 가 현재 동작중인 Activity 일 때(백스택의 TOP 에 존재), onNewIntent() 메서드를 통해 Intent 값을 받는다.
    • FLAG_ACTIVITY_CLEAR_TOP
      • 현재 Task 에서 이미 실행 중인 Activity 를 실행시킬 때, 해당 Activity 의 새 Instance 를 생성하지 않고 Task 내에 TOP 에 존재하는 다른 Activity 들을 모두 제거 한다. 그리고 전달하려는 Intent 값은 onNewIntent() 메서드를 통해 Resume 된 해당 Activity(TOP에 위치) 로 전달된다.
      • FLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_NEW_TASK결합하여 자주 사용 된다. 함께 쓰면 다른 Task 에서 이미 존재하는 Activity 를 Intent 값에 반응 할 수 있는 위치로 옮길 수 있다.

참고자료 (출처)

https://codechacha.com/ko/activity-backstack/

https://developer.android.com/guide/components/activities/tasks-and-back-stack

반응형

'Android Developer' 카테고리의 다른 글

[Android] APK 용량 줄이기  (0) 2019.10.08
[Android] AsyncTask  (0) 2019.08.02
[Android] Log  (0) 2019.07.10
[Android] Activity의 LaunchMode  (0) 2019.07.10
[Android] 난독화(Proguard)  (0) 2019.05.14