상세 컨텐츠

본문 제목

그림으로 이해하는 Activity LaunchMode 실험👩‍🔬

안드로이드 개발 지식

by yebon.kim 2021. 2. 20. 20:05

본문

반응형

 

  저는 AndroidManifest에서 한 Activity가 여러 번 인스턴스화 되는 것을 피하기 위해 SingleTask 또는 SingleInstance를 구분하지 않고😓 적어주곤 했습니다. 특히 비밀번호 재입력 같이 똑같은 뷰에서 로직만 조금 달라져야 할 때 자주 사용하였습니다.

  각 launchMode를 헷갈리지 않고 쓰기 위해 테스트 해보고 정리해보았습니다.

 

관련 Android Docs 링크 : https://developer.android.com/guide/components/activities/tasks-and-back-stack

아래 테스트 내용들은 깃헙 레포에서 브랜치별로 확인하고 다른 궁금한 것들을 테스트해보면 재밌을 것 같습니다. 🤗

https://github.com/yebonkim/test-launchmode

 

Launch Mode

- Standard

Standard는 AndroidManifest의 launchMode의 기본값으로 launchMode 필드를 생략해도 설정됩니다. 해당 launchMode가 설정된 Activity는 한 Task 안에서도 여러 번 인스턴스화 될 수 있으며 여러 다른 Task안에서도 속할 수 있습니다. 아래 예시의 B Activity가 standard 모드의 예입니다. Task 1 에서도 여러 번 인스턴스화 되어있으며 Task 2 에도 존재하고 있습니다.

 

stadard B Activity

    final static String STARTED_CNT = "STARTED_CNT";
    final static int RETRY_CNT = 3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int startedCnt = getIntent().getIntExtra(STARTED_CNT, 0);

        Intent recursiveIntent = new Intent(this, MainActivity.class);
        recursiveIntent.putExtra(STARTED_CNT, ++startedCnt);
        if (startedCnt < RETRY_CNT) {
            startActivity(recursiveIntent);
        }
    }

[소스 1]

 

위와 같은 소스로 같은 Activity를 여러 번 띄웠을 때 onNewIntent를 실행되지 않으며 onCreate 만 실행이 되었습니다. 또한 아래와 같이 한 스택 안에 여러 번 인스턴스 화 된 것을 확인할 수 있습니다.

Standard Activity를 여러 번 start한 경우


- SingleTop

  말 그대로 이 launchMode를 설정한 Activity는 Task의 Top에서 연달아 존재할 수 없습니다. Top에서는 Single, 1개만 존재할 수 있습니다. Activity의 인스턴스가 Task의 최상단에 있을 경우에 해당 Activity를 다시 startActivity할 경우 onCreate가 불리지 않고 onNewIntent가 호출되며 Acitivity의 인스턴스가 Task에 추가되지 않습니다. 기존 instance를 재활용한다고 생각할 수 있습니다. 하지만 Top이 아닌 Task의 다른 위치에서는 여러 번 인스턴스화 될 수 있습니다.

singleTop B Activity

  위와 같이 B Activity에 singleTop이 설정되어있는 경우 왼쪽 모형은 불가능하며 오른쪽 모형은 가능합니다.

launchMode를 바꾸고 [소스 1]을 재실행해보면 아래와 같은 결과를 얻을 수 있습니다.

singleTop Activity를 여러 번 start한 경우


- SingleTask

  singleTop이 상위에 있을 때만 기존 인스턴스로 라우팅해준다면, singleTask는 Task내의 먼저 시작된 자신에게로 라우팅해줍니다. 즉 Task내에 자신이 존재한다면 자신으로 라우팅하고, 없다면 새 인스턴스를 추가합니다. 때문에 위 두 launchMode보다 이 singleTask모드가 모호한 부분이 있었습니다. 아래 실험을 통해서 이 launchMode의 특이한 점들을 확인해보았습니다.

 

1. SingleTask로 설정된 Activity로 onNewIntent될 때, 그 중간에 있는 Activity들은 모두 onDestroy된다.

 

  MainActivity에 SingleTask가 설정된 경우 왼쪽의 Task 상황에서 MainActivity를 startActivity하면 중간의 Second, ThirdActivity는 onDestroy되고 오른쪽 Task모형처럼 MainActivity만 남게 됩니다.

SingleTask로 다시 라우팅되는 과정의 Activity들은 onDestroy된다.

위 그림에서 각 3개의 Activity는 아래와 같은 설정을 가지고 있습니다.

  • MainActivity(A TaskAffinity, SingleTask)

  • SecondActivity(A TaskAffinity, Standard)

  • ThirdActivity(A TaskAffinity, Standard)

Main -> Second -> Third -> Main

 

  순으로 호출하면 그림과 같은 결과를 얻을 수 있습니다. 위 실험은 비교적 간단하여 로그캣으로만 결과를 관찰하였습니다.

ThirdActivity onDestroy가 MainActivity onNewIntent보다 늦게 불렸다는 변수가 있지만 결론적으로 Second, ThirdActivity는 onDestroy되었습니다.

(참고로 Galaxy s8+(Android 9)에서 5번 실험하여도 아래 결과의 순서는 똑같았습니다.)

 

SingleTask로 다시 라우팅되는 과정의 Activity들은 onDestroy된다.


2. 다른 Task안에 있는 singleTask Activity에게도 라우팅된다.

 

  위와 같은 실험을 하기 위해서 taskAffinity를 달리하는 Activity를 하나 추가하였습니다. 또 새로 생성되는 Acitivity는 이전 Activity의 Task를 따라가는 점을 이용하여 아래와 같은 테스트 케이스를 만들었습니다.

 

우선 각 4개의 Activity는 아래와 같은 설정이 되어있습니다.

  • MainActivity(A TaskAffinity, singleTask)
  • SecondActivity(A TaskAffinity, standard)

  • ThirdActivity(A TaskAffinity, standard)

  • OtherTaskActivity(B TaskAffinity, standard)

Main -> Second  -> Other -> Third -> Main

 

위와 같은 설정으로 실험을 하면 아래와 같은 결과를 얻습니다.

다른 Task안에 있는 singleTask Activity에게도 라우팅된다.

  위와 같이 ThirdActivity 까지 호출한 경우 왼쪽 모형과 같은 상황이 되며 ThirdActivity에서 다시 MainActivity를 부를 경우 A Task 안으로 라우팅 됩니다. 독특한 점은 A Task의 상위 Activity인 SecondActivity만 onDestory되었으며 B Task의 Activity들은 남아있었습니다.

  위 실험을 adb를 통해서 관찰하면

A Task
B Task

 

  즉 singleTask를 지정할 경우 Activity는 전체 Task에서 하나만 존재할 수 있습니다. 또 라우팅을 시작하는 Task에 있는 Activity들은 종료되지 않으며(B Task) 라우팅이 도착하는 곳에 있는 기존에 있던 singleTask상위의 Activity들은 onDestroy됩니다.(A Task) (이 부분은 앞으로도 예외가 있다면 추가하겠습니다. 또 반대케이스를 알고 계신다면 댓글로 알려주세요😊)


- SingleInstance

  singleInstancesingleTask와 비슷하나 singleInstance로 지정된 Activity가 있는 Task에는 다른 Activity가 추가되지 않는다는 점이 다릅니다. 따라서 A activity가 singleInstance이고 startActivity를 시작한다면 다음 Activity는 다른 Task안에 위치하게 됩니다. 이 차이로 인해 singleTask에서 한 실험의 1번은 결과가 달라지게 됩니다.

 

아래와 같이 Activity 3개를 설정해두었습니다.

  • MainAcitivty(A TaskAffinity, singleInstance)

  • SecondActivity(A TaskAffinity, standard)

  • ThirdActivity(A TaskAffinity, standard)

Main -> Second -> Third -> Main

 

  위와 같은 순서로 Activity들을 호출하였을 때 Second, Third는 다른 Task로 분리가 됩니다. 이 후 ThirdActivity에서 MainActivity를 호출하였을 때 A Task의 MainActivity로 라우팅되어 onNewIntent가 호출됩니다.

  이 때 singleTask의 2번 실험에서 라우팅이 시작되는 Task의 Activity들은 onDestroy되지 않았던 것처럼, singleInstance  역시 다른 Task에 다른 Activity들이 분리되어있으니 다른 Activity들이 onDestroy되지 않습니다.

singleInstance는 Task안에 자신만 존재하게 된다.

  즉 위 그림과 같은 상황이 되어 adb로 관찰하여도 결과는 같습니다. SecondActivity, ThirdActivity 는 MainActivity와 다른 Task에 위치하고 있는 것을 확인할 수 있습니다.

singleInstance는 Task안에 자신만 존재하게 된다.


(+ singleInstance 추가 실험)

 

  그렇다면 다른 Activity가 singleInstance가 선언된 Activity를 호출하여도 Task가 분리될 수 있을까?

 

아래 테스트 순서를 통해 위의 상황도 테스트해보았습니다. 똑같이 Activity 3개를 설정해두었습니다.

  • MainAcitivty(A TaskAffinity, standard)

  • SecondActivity(A TaskAffinity, singleInstance)

  • ThirdActivity(A TaskAffinity, standard)

Main -> Second -> Third -> Main

  위와 같은 세팅으로 테스트를 할 경우 SecondActivity는 다른 Task에 분리되며 그 이후에 실행된 ThirdActivity는 A Task로 다시 돌아오는 것을 알 수 있습니다.

SecondActivity 고립시키기😏

adb로 확인해 보아도 같은 결과를 볼 수 있습니다.

A Task
B Task


  항상 Android Docs 첫 부분에 있어 자주 읽어도 대강만 알고 있던 launchMode에 대해 여러 테스트를 해보았습니다.👩‍💻이번 테스트가 꽤 재미있어서 더 오래 기억할 수 있을 것 같습니다.☺️ 다음에는 비슷한 기능을 하는 Intent Flag에 대해 알아보겠습니다.

반응형

댓글 영역