Android N 멀티윈도우 - 어떻게 대응해야 할까?



개인 광고 영역

Edit. Preivew 2가 나오면서 일부 API 이름이 변경되었습니다.

Edit. 2020. 04. 12 github example url 변경 및 코드 최신화


안드로이드 N부터 Multi window를 지원하게 됩니다.
단순히 Multi window이고 구글 설명상 Activity lifecycle을 그대로 따를 것이라고 합니다.
이번에는 예제를 통해서 이러한 변화가 어떻게 적용되는지 살펴보겠습니다.

지난 정리 글 :

API 문서 :


테스트 코드 주소

Android Studio 3.6.2에 맞게 수정한 내용을 적용하였습니다.

Multi window example code - GitHub

안드로이드 멀티 윈도우

멀티 윈도우 적용 시 달라지는 점을 확인하기 위해서 다음과 같은 테스트를 해보았습니다.

  • onResume/onPause 호출 시점
  • 창 크기 변경에 따른 lifecycle
  • 창 크기 변경 - configChange를 적용하였을 경우
  • 전체적인 정리


onResume/onPause 호출 시점
일반적으로는 Activity가 활성화되고, 비활성화 시에 호출되게 됩니다.
화면이 완전히 사라진다면 onStop이 호출되겠죠.
멀티 윈도우가 적용되는 N에서는 onResume/onPause가 생각보다 많이 호출된다고 합니다.
onResume/onPause가 호출되는 시점을 확인하기 위해서 다음을 테스트해보았습니다.

다음 테스트 결과는 위쪽에 최신 데이터를 가지게 됩니다.

Screenshot-01

정상적으로 앱이 실행되었습니다.
onCreate -> onStart -> onResume 가 순서대로 동작합니다.

Multi Window 간 화면 전환을 시도하였을 때 다음과 같은 동작이 추가되었습니다.
onPause -> onResume -> onPause -> …
onResume(활성화) 상태에서 onPause(비활성화) 상태로의 변환이 계속적으로 일어남을 확인할 수 있습니다.

이를 그림으로 그리면 다음과 같습니다.
창간의 전환이 일어나게 되면 빨간 부분의 onResume / onPause 가 계속적으로 호출되게 됩니다.
특히나 동영상의 onPause에서 동영상 일시 정지를 하게 되는 경우가 많을 것 같습니다.
이 경우에는 꼭 onPause가 아니라 onStop으로 이동이 필요하다고 생각됩니다.(구글 팁의 lifecycle에서 자세하게 나옵니다.)

Screenshot-02


이로 인해 onResume, onPause 간에서는 동작을 최소한으로 줄이는 노력이 필요해 보입니다.


창 크기 변경에 따른 lifecycle
창의 크기를 변경할 수 있습니다.
분활 된 창의 가운데 부분을 왼쪽/오른쪽, 상/하로 이동하게 되면 창이 커지고 줄어들게 됩니다.
이때의 창의 크기가 변하는데 실제 lifecycle은 어떻게 동작하는지 살펴보겠습니다.

Screenshot-03

별다른 것 없어 보입니다. 실제로는 다음을 무한 루프 돌게 됩니다.
onCreate -> onStart -> onResume

onResume 상태를 기준으로 전체적으로 다시 보게 되면
onResume -> onPause(창 크기 변경 시작) -> onStop -> onDestroy -> onCreate(창 크기 변경 종료) -> onStart -> onResume

앱이 onCreate부터 처음부터 다시 시작하고 있습니다.
이동 중에는 아래의 flowchart처럼 동작하게 됩니다.

Screenshot-04

다시 정리하면 Android N 대응을 하지 않을 경우에는 onDestroy -> onCreate가 계속적으로 동작하게 됩니다.


창 크기 변경 - configChange를 적용하였을 경우

5 tips for preparing for Multi-Window in Android N에서 보았던 configChanges 코드를 적용해보겠습니다.

configChanges를 적용하였을 경우 lifeCycle이 어떻게 변화되는지 살펴보겠습니다.

우선 xml에 다음의 코드를 추가하였습니다.

android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"

java 코드도 추가했습니다.

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // ...

}

Screenshot-05

바로 위에서 보았던 이미지와는 많이 다름을 확인할 수 있습니다.
크게 onPause -> onDestroy 가 호출되지 않았습니다.
코드 상으로 onConfigurationChanged가 호출이 되고 있습니다.
그림 상으로는 아래와 같이 표현 할 수 있겠습니다.

Screenshot-06

그리고 숫자 1이 표시되고 있는데 이 값은 API의 Configuration API 문서

Configuration.SCREENLAYOUT_SIZE_SMALL

화면이 축소된 상태이므로 size small이 호출됩니다.

전체적인 정리
내용을 정리해보겠습니다.
멀티윈도우 간 화면 전환 시 호출되는 순서
onPause -> onResume -> onPause -> …

Android N 대응 존 앱에서 창 사이즈를 변경 시
onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
이 경우에는 전체적인 lifeCycle이 다시 동작하게 됩니다.

configure 설정을 하였을 경우
onResume인 상태에서 -> onConfigurationChanged
onConfigurationChanged만 호출되게 됩니다.

창 사이즈가 줄어들기 전과 복구된 상태에서는 onConfigurationChanged에서 다음의 코드가 호출됩니다.

Configuration.SCREENLAYOUT_SIZE_NORMAL
Configuration.SCREENLAYOUT_SIZE_SMALL

Size가 변경이 일어나게 되면 Normal -> small 이 호출됩니다.
inMultiWindow 상태도 false -> true로 변경되게 됩니다.

Screenshot-07


주요 코드

xml에서는 다음의 코드를 적용하였습니다.

참고 : 반대로 동작하지 않을 경우 screenOrientation을 강제로 지정하는 경우(가로 고정/세로 고정)에는 Multi window가 동작하지 않습니다.

<!-- Multi window support example -->
<activity
    android:name=".multiwindow.MultiWindowActivity"
    android:resizeableActivity="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
    android:theme="@style/AppTheme.NoActionBar" />

<!-- Multi window freeform mode example -->
<!-- 테스트 하려고 넣었지만 실제 동작하지 않네요 -->
<activity
    android:name=".multiwindow.FreeformModeActivity"
    android:resizeableActivity="true"
    android:theme="@style/AppTheme.NoActionBar">
    <layout
        android:defaultHeight="500dp"
        android:defaultWidth="600dp"
        android:gravity="top|end"
        android:minimalHeight="450dp"
        android:minimalWidth="300dp" />

    <!-- Preview 2 change -->
    <!-- Remove API Name : android:minimalSize -->
    <!-- Add API Name : android:minimalWidth -->
    <!-- Add API Name : android:minimalHeight -->
</activity>


Java 코드에서는

Activity 기반에서는 다음의 코드를 통해 Multi window 상태를 알 수 있습니다.
아래 2개 코드가 존재하고 있는데 boolean 값을 return 해주고 있습니다.

/*
 * 멀티 윈도우 상태를 가져옵니다.
 */
// Preview 2 API 이름 변경
// boolean inMultiWindow()
boolean isInMultiWindowMode()
/*
 * 멀티 윈도우 상태를 변경합니다.
 * true -> 멀티윈도우로 전환합니다.
 * false -> 멀티윈도우에서 빠져나옵니다.
 */
// Preview 2 API 이름 변경
// void onMultiWindowChanged(boolean isMultiWindow)
void onMultiWindowModeChanged(boolean isMultiWindow)

제가 테스트 한 코드는 아래와 같습니다.

multiWindowAdapter.addItem("onResume() isInMultiWindowMode " + isInMultiWindowMode(), true);


마무리

멀티 윈도우에 대해서 전반적인 내용을 살펴보았습니다.
API 문서를 정리하였고, Freeform 모드를 적용해보기도 하였습니다.



onResume/onPause와 configChanges에 대한 대응은 꼭 필요하다고 생각됩니다.
configChanges를 적용하지 않으면 앱의 LifeCycle가 처음부터 다시 동작하게 됩니다.
그것도.. 실시간으로 일어나게 되겠습니다. 손을 놓을 때마다…

다음의 문서는 정말 중요한 문서라고 생각됩니다.
이 문서의 내용을 꼭 습득하시기 바랍니다.
5 tips for preparing for Multi-Window in Android N


테스트 코드 주소

Android Studio 3.6.2에 맞게 수정한 내용을 적용하였습니다.

Multi window example code - GitHub



About Taehwan

My name is Taehwan Kwon. I have developed Android for 6 years and blog has been active for eight years.

Comments