액티비티 시리즈 - 3) Task

woga·2022년 5월 29일
0

Android 공부

목록 보기
28/49
post-thumbnail

오늘의 시리즈는 "Task"다.

Task?

태스크는 간단하게 액티비티 작업 묶음 단위라고 보면 된다.

예를 들면, 사진 리스트를 보고 PictureListActivity, 사진 상세를 살펴보고 PictureDetailActivity, 사진을 올리려고 카메라를 실행시킨다(카메라 앱의 CameraActivity)

이러면 3개의 액티비티가 하나의 태스크가 되는데, 2개의 앱이 하나의 태스크가 되었다.

예시로 봤듯이, 앱과 태스크는 일대잉 대응이 아니다. 여러 개의 앱이 하나의 태스크가 될 수도 있고, 필요하면 하나의 앱에서도 태스크를 여러 개 가질 수 있다.

백스택

액티비티는 백 스택(back stack)이라 불리는 스택에 차례대로 쌓인다. 태스크와 백 스택은 용어를 혼용해서 쓰기도 하는데 태스크는 액티비티 모임이고 백 스택은 그 모임이 저장된 방식을 의미하는 것으로 이해하면 된다.

스택은 말 그대로 LIFO(Last-In-First-Out) 방식으로 쌓이고 사라진다.

참고로 스택 구조라서 순서를 바꿀 수 없다고 말하지만, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT 플래그를 사용하면 순소를 조정할 수 있다.
(나는 이 플래그를 잘 사용하지 않는다 스택 순서가 꼬일까봐.. 그치만 예외 사항이 있을 수 있다)

그림처럼 쌓이다가 BACK 키를 누르면 가장 TOP에 있는 Activity 3이 POP 된다.

태스크 관리 필요

보통 startActivity()를 실행해서 스택에 추가하고 백 키로 제거해가면 아무 일도 없지만, 실제 앱에서는 다양한 경로로 액티비티를 접근하기 때문에 내비게이션(화면 흐름)이 꼬이는 경우가 많다.

  • ex1 : 캘린더앱

캘린더앱에서 달력 화면(1) -> 일정 상세 화면(2) -> 일정 수정(3)으로 간다해보자. 근데 여기서 사용자가 홈 키를 눌러서 태스크를 백그라운드로 보냈는데, 홈 스크린에 일정 목록 앱 위젯이 있고 여기서 일정 상세 화면(2)으로 이동할 수 있다고 어떻게 될 것인가?

(1) -> (2) -> (3) 으로 쌓여져있던 스택에 (2)를 추가하면 될까? 아니면 일정 수정(3) 액티비티를 스택에서 날리고 일정 상세 화면 (2) 액티비티를 로딩하게 하면 될까? 물론 정해진 답이 있는 건 아니므로 팀 내에서 규칙을 정하거나 의논한 할 필욘 있다.

  • ex2 : 인*타

사진 공유 앱(*스타)에서 사진 목록 화면 (A)에서 등록자 프로필을 클릭하면 등록자의 프로필을 포함한 등록자의 사진 목록 화면 (B)으로 이동한다.

B 화면의 사진들에는 [좋아요]를 선택한 다른 사용자 프로필 이미지들을 볼 수 있는데, 이 이미지를 클릭하면 그 사용자의 사진 목록 화면(B)로 이동한다.

계속 반복해서 사용자의 사진 목록 화면이 쌓일 수 있고, 아니면 같은 화면에서 사진 목록만 갱신할 수도 있다. 어느 쪽이 올바르고 원하는 방식일지는 고민이 필요하다.



이렇게 각 앱에서 원하는 UX나 플로우, 내비게이션이 있는데, 태스크의 동작 방식을 이해하지 못하면 사용자가 보이려는 화면이 아닌 엉뚱한 화면을 보여주는 경우가 생긴다. 태스크의 동작 방식은 이해하기 쉽지 않기 때문에 많은 시행 착오를 겪을 수도 있다.

태스크의 상태

태스크는 2가지 상태가 있다.

  • 화면에 포커스되어 있는 포그라운드 상태
  • 화면에 보이지 않는 백그라운드 상태

또한, 앱 아이콘, 숏컷, 앱 위젯, 노티피케이션을 통해 새로운 포그라운드 태스크가 될 수 있다.


  • 포그라운드

디바이스 홈 키로 혹은 제스쳐로 언제든 백그라운드로 이동할 수 있다.

  • 백그라운드

히스토리 기록이나 앞서 언급한 다양한 경로로 언제든 포그라운드로 이동할 수 있다.

참고로 홈 화면에 나와있을 때는 launcher가 포그라운드 태스크이다.

이런 상태를 갖고 있으면 당연히 이 상태를 이동하는 메서드가 있을 거라 예상되지 않는가? 맞다.

포그라운드에서 백그라운드로 태스크 이동

Acitivity의 moveTaskToBack(boolean nonRoot) 메서드가 있다. nonRoot 파라미터에 true가 들어가면 어느 위치에서건 백그라운드로 이동할 수 있고, false면 태스크 루트일 때만 백그라운드로 이동 가능하다.

즉, boolean이 뭐든 백그라운드로 이동 가능한 메서드다

파라미터가 부정어라 헷갈리지만, moveTaskToBack(boolean onlyRoot)라 생각하면 이해하기 쉽다.

  • ex: 패스코드

이 메서드를 쓸 경우를 생각해보면, 보안이 필요한 앱에 패스코드 화면을 띄울 때다.

앱이 포그라운드에 올 때마다 원래 보여지는 액티비티 위로 패스코드 입력 액티비티가 전면에 뜬다.

패스코드가 맞게 입력 되면 -> 패스코드 액티비티 종료 및 원래 액티비티로 이동

맞게 입력 되지 않으면 -> 원래 액티비티로 돌아갈 수 있는 방법이 없어야 함

따라서 BACK 키를 누를 때도 원래 액티비티가 보이지 않게 태스크를 백그라운드로 이동하는 방법을 사용한다.

패스코드 액티비티 속 onBackPressed() 메서드를 override해서 moveTaskToBack(true)를 호출하면 된다.

백그라운드에서 포그라운드로 태스크 이동

그 반대도 있다. 그러나 액티비티가 보이지 않는 상태이기 때문에 ActivityManagermoveTaskToFront(int taskId, int flags)를 사용하면 된다.

허니콤부터 사용 가능하고 android.permission.REORDER_TASKS 퍼미션이 필요하다.

dumpsys 명령어로 태스크 확인

화면이 바뀌는 것을 눈으로 직접 보면서 테스트하면 태스크가 정상적으로 도작하는지 확인하기 어렵다.

백 키로 전환하는 화면들은 마치 하나의 스택처럼 보이는데, 이 화면들이 동일한 태스크라고 확신할 수 없다.

그렇기 때문에 태스크를 확인할 때는 adb shell에서 dumpsys 명령어를 활용하면 된다.

  • adb shell dumpsys activity activities
  • adb shell 내에서 dumpsys activity activities

마지막 옵션인 activities는 a로 줄여 쓸 수도 있다.

출력 결과가 많을 경우는 아래 명령어를 통해 파일로 저장할 수 있다.

  • adb shell dumpsys activity a > tasks.txt

그래도 출력 결과가 많기 때문에 해당 앱 관련 내용만 보려고 할 때는 grep 명령어를 활용하면 된다.

  • dumpsys activity a | grep com.example.android.supportv4

dumpsys 명령어로 포커스된 액티비티를 찾을 수도 있다.

  • adb shell dumpsys activity a | grep mFocusedActivity

그 외..

taskAffinity와 액티비티 Intent Flags는 다른 블로그에서는 정리를 잘 해뒀으니 참고하자!

마치며..

태스크와 인텐트 플래그들은 사실 현재 팀에서 맡은 업무를 처리하고자 할 때 공부해서 썼던 기억이 있다. 그 때는 "태스크는 이런 개념, 이럴 때 속성을 부여하고 액티비티 인텐트 넘길 때는 이렇게." 요런식으로 인지하고 넘어갔는데 다시 책을 읽으면서 자세히 알고 정리되니깐 이제야 태스크에 대해 안 기분이다.

또한, 실제로 내가 개발하고 있는 앱의 시작 액티비티 런치모드 속성도 singlTask로 지정되어 있는데 이렇게 지정하지 않으면, 딥링크를 실행할 때 새로운 task로 오픈되는게 아니라 현재 구동되고 있는 타 앱의 task 내에서 실행된다. (물론 이렇게 안되게 따로 처리한 앱들도 있지만, 모든 앱에서 이런 코드처리를 할거라고 기대하면 안되기 때문에..)

이 현상 때문에 task 관리를 잘해야한다고 느꼈고, 안드로이드 모바일 앱 개발자라면 알아야하는 기본이라고 생각이 들었다.

profile
와니와니와니와니 당근당근

0개의 댓글