멀티 윈도우 지원

멀티 윈도우 모드를 통해 여러 앱이 같은 화면을 동시에 공유할 수 있습니다. 앱은 나란히 또는 상하로 배치(화면 분할 모드), 다른 앱에 오버레이된 작은 창에 하나의 앱이 있거나(PIP 모드), 이동과 크기 조절이 가능한 별도의 창에 있는 개별 앱 (자유 형식 모드)일 수 있습니다.

그림 1. 화면 분할 모드에서 두 앱을 나란히 표시합니다.

사용자 환경은 Android OS 버전과 기기 유형에 따라 달라집니다.

  • Android 7.0 (API 수준 24)에는 소형 화면 기기에서 화면 분할 모드가, 일부 기기에서 PIP 모드가 도입되었습니다.

    화면 분할 모드는 화면을 두 개의 앱으로 채우고, 이 앱을 나란히 또는 상하로 표시합니다. 사용자는 두 앱을 구분하는 구분선을 드래그하여 한 앱을 다른 앱보다 더 크게 또는 더 작게 만들 수 있습니다.

    PIP 모드를 사용하면 사용자가 다른 앱과 상호작용하는 동안 동영상을 계속 재생할 수 있습니다(PIP 모드 지원 참고).

    대형 화면 기기 제조업체는 자유 형식 모드를 사용 설정할 수 있으며, 이 경우 사용자가 각 활동의 크기를 자유롭게 조절할 수 있습니다.

    활동의 최소 허용 치수를 지정하여 앱이 멀티 윈도우 모드를 처리하는 방식을 구성할 수 있습니다. resizeableActivity="false"를 설정하여 앱의 멀티 윈도우 모드를 사용 중지할 수도 있으며, 이 경우 시스템은 항상 앱을 전체 화면으로 표시합니다.

  • Android 8.0 (API 수준 26)은 PIP 모드를 소형 화면 기기로 확장합니다.
  • Android 12 (API 수준 31)에서는 멀티 윈도우 모드를 표준 동작으로 설정합니다.

    큰 화면(sw >= 600dp)에서 플랫폼은 앱 구성에 관계없이 멀티 윈도우 모드의 모든 앱을 지원합니다. resizeableActivity="false"인 경우 디스플레이 크기를 수용하기 위해 필요한 경우 앱이 호환성 모드로 전환됩니다.

    작은 화면(sw < 600dp)에서 시스템은 활동의 minWidth minHeight를 확인하여 활동이 멀티 윈도우 모드에서 실행될 수 있는지 판단합니다. resizeableActivity="false"인 경우 앱은 최소 너비 및 높이와 상관없이 멀티 윈도우 모드에서 실행되지 않습니다.

    참고: 기기 제조업체는 이러한 동작을 재정의할 수 있습니다.

화면 분할 모드

사용자는 다음을 수행하여 화면 분할 모드를 활성화할 수 있습니다.

  1. 최근 화면을 엽니다.
  2. 앱을 스와이프하여 뷰로 가져옵니다.
  3. 앱 제목 표시줄에서 앱 아이콘을 누릅니다.
  4. 화면 분할 메뉴 옵션을 선택합니다.
  5. 최근 화면에서 다른 앱을 선택하거나 최근 화면을 닫고 다른 앱을 실행합니다.

사용자는 창 구분선을 화면 가장자리(예: 위 또는 아래, 왼쪽 또는 오른쪽)로 드래그하여 화면 분할 모드를 종료할 수 있습니다.

인접 항목 실행

앱이 인텐트를 통해 콘텐츠에 액세스해야 한다면 FLAG_ACTIVITY_LAUNCH_ADJACENT를 사용하여 인접한 화면 분할 창에서 콘텐츠를 열면 됩니다.

FLAG_ACTIVITY_LAUNCH_ADJACENT는 화면 분할 모드로 실행되는 앱이 인접한 창에서 활동을 실행할 수 있도록 Android 7.0 (API 수준 24)에서 도입되었습니다.

Android 12L (API 수준 32) 이상에서는 전체 화면을 실행하는 앱이 화면 분할 모드를 활성화한 다음 인접한 창에서 활동을 실행할 수 있도록 플래그 정의를 확장했습니다.

인접 활동을 실행하려면 FLAG_ACTIVITY_LAUNCH_ADJACENTFLAG_ACTIVITY_NEW_TASK와 함께 사용합니다. 예를 들면 다음과 같습니다.

Kotlin

fun openUrlInAdjacentWindow(url: String) {
    Intent(Intent.ACTION_VIEW).apply {
        data = Uri.parse(url)
        addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or
                           Intent.FLAG_ACTIVITY_NEW_TASK)
    }.also { intent ->
        startActivity(intent)
    }
}

Java

public void openUrlInAdjacentWindow(String url) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse(url));
    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

멀티 윈도우 모드의 활동 수명 주기

멀티 윈도우 모드는 활동 수명 주기를 변경하지 않습니다. 그러나 멀티 윈도우에서 재개되는 앱의 상태는 Android 버전에 따라 다릅니다.

다중 재개

Android 10(API 수준 29) 이상 버전은 다중 재개를 지원합니다. 기기가 멀티 윈도우 모드에 있을 때 모든 활동은 RESUMED 상태로 유지됩니다. 투명한 활동이 활동 위에 있거나 활동에 포커스를 맞출 수 없는 경우(예: PIP 모드) 활동이 일시중지될 수 있습니다. 알림 창이 열려 있는 경우와 같이 특정 시점에 포커스가 맞춰진 활동이 없을 수도 있습니다. onStop 메서드는 평소와 같이 작동합니다. 이 메서드는 활동이 화면에서 사라질 때마다 호출됩니다.

Android 9 (API 수준 28)를 실행하는 일부 기기에서도 다중 재개를 사용할 수 있습니다. Android 9 기기에서 다중 재개하도록 선택하려면 다음 매니페스트 메타데이터를 추가합니다.

<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />

지정된 기기가 이 매니페스트 메타데이터를 지원하는지 확인하려면 기기 사양을 참고하세요.

Android 9

Android 9(API 수준 28) 이하의 멀티 윈도우 모드에서는 사용자가 최근에 상호작용했던 활동만 지정된 시간에 활성 상태가 됩니다. 이 활동이 최상위로 간주되고 RESUMED 상태의 유일한 활동이 됩니다. 그 외에 표시되는 모든 활동은 STARTED이지만 RESUMED는 아닙니다. 그러나 시스템은 화면에 표시되지만 아직 다시 시작되지 않은 이러한 활동에 표시되지 않은 활동보다 더 높은 우선순위를 부여합니다. 사용자가 표시된 활동 중 하나와 상호작용하면, 해당 활동이 다시 시작되고 이전의 최상위 활동이 STARTED 상태에 들어갑니다.

단일 활성 앱 프로세스 내에 여러 활동이 있는 경우 z 순서가 가장 높은 활동이 재개되고 나머지는 일시중지됩니다.

구성 변경

사용자가 앱을 멀티 윈도우 모드에 놓으면 시스템은 구성 변경 처리에 지정된 대로 구성 변경을 활동에 알려줍니다. 이 동작은 사용자가 앱의 크기를 조정하거나 앱을 전체 화면 모드로 다시 전환할 때도 발생합니다.

기본적으로 이 같은 변경의 활동 수명 주기 영향은 기기 방향이 세로에서 가로로 전환되었음을 시스템이 앱에 알려줄 때와 동일합니다. 단, 기기 방향이 전환된 것이 아니라 기기 치수가 변경되었다는 것이 다릅니다. 구성 변경 처리에서 설명한 대로, 활동은 스스로 구성 변경을 처리하거나, 시스템이 활동을 소멸시키고 새 치수로 다시 활동을 생성하도록 허용할 수 있습니다.

사용자가 창의 크기를 조정하여 한쪽 치수를 더 크게 만드는 경우, 시스템은 사용자 작업에 맞게 활동의 크기를 조정하고 필요한 경우 구성 변경을 수행합니다. 앱이 새로 노출되는 영역에 그리기를 수행할 때 지연이 발생하는 경우, 시스템은 windowBackground 속성 또는 기본 windowBackgroundFallback 스타일 속성에 지정된 색으로 이 영역을 임시로 채웁니다.

독점적 리소스 액세스

다중 재개 기능을 지원하는 데 도움이 되는 새로운 수명 주기 콜백 onTopResumedActivityChanged()가 있습니다.

이 메서드는 활동이 최상위 재개 활동 지위를 얻거나 상실하는 경우 호출됩니다. 이 메서드는 활동이 마이크 또는 카메라와 같은 공유 싱글톤 리소스를 사용하는 시기를 파악하는 데 중요합니다.

Kotlin

override fun onTopResumedActivityChanged(topResumed: Boolean) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

Java

@Override
public void onTopResumedActivityChanged(boolean topResumed) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

공유 하드웨어 제거와 같은 여러 다른 이유로 앱에서 리소스가 손실될 수 있습니다.

어떤 경우이든 앱은 사용 가능한 리소스에 영향을 주는 이벤트 및 상태 변경을 적절하게 처리해야 합니다.

카메라를 사용하는 앱의 경우 CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged()는 카메라에 액세스해 볼 수 있는 적절한 때를 알려주는 힌트를 제공합니다. 이 메서드는 Android 10(API 수준 29)부터 사용할 수 있습니다.

resizeableActivity=false는 독점적인 카메라 액세스를 보장하지 않습니다. 이는 카메라를 사용하는 다른 앱이 다른 디스플레이에서 열릴 수 있기 때문입니다.

멀티 윈도우 모드의 카메라

그림 2. 멀티 윈도우 모드의 카메라

앱에서 포커스가 해제될 때 카메라를 해제할 필요는 없습니다. 예를 들어 사용자가 새로 포커스를 맞춘 최상위 재개 앱과 상호작용하는 동안 카메라 미리보기가 계속되는 것이 좋습니다. 최상위 재개 앱이 아니라면 앱에서 카메라를 계속 실행해도 괜찮지만 연결 해제 사례를 적절하게 처리해야 합니다. 최상위 재개 앱이 카메라를 사용하려는 경우 카메라를 열면 됩니다. 다른 앱에서는 액세스가 손실됩니다. 앱에서 다시 포커스를 가져오면 앱이 카메라를 다시 열 수 있습니다.

앱이 CameraDevice.StateCallback#onDisconnected() 콜백을 수신하면 카메라 기기의 후속 호출에서 CameraAccessException이 발생합니다.

다중 디스플레이

Android 10(API 수준 29)은 보조 디스플레이에서의 활동을 지원합니다. 다중 디스플레이를 사용하는 기기에서 활동을 실행하는 경우 사용자는 하나의 디스플레이에서 다른 디스플레이로 활동을 이동할 수 있습니다. 다중 재개는 멀티스크린 시나리오에도 적용됩니다. 여러 활동이 동시에 사용자 입력을 수신할 수 있습니다.

앱은 실행될 때 또는 다른 활동을 만들 때 실행할 디스플레이를 지정할 수 있습니다. 이 동작은 매니페스트 파일에 정의된 활동 시작 모드와 활동을 실행하는 항목에 설정된 인텐트 플래그 및 옵션에 따라 달라집니다. 자세한 내용은 ActivityOptions를 참고하세요.

활동이 보조 디스플레이로 이동하는 경우 컨텍스트 업데이트, 창 크기 조절, 구성 및 리소스 변경을 실행할 수 있습니다. 활동이 구성 변경을 처리하면 onConfigurationChanged()로 알림을 받습니다. 그렇지 않으면 활동이 다시 실행됩니다.

구성 변경이 처리된 경우 활동은 onCreateonConfigurationChanged에서 현재 디스플레이를 확인해야 합니다. 디스플레이가 변경되면 리소스 및 레이아웃도 업데이트되어야 합니다.

활동에 선택된 시작 모드에서 다중 인스턴스가 허용되는 경우 보조 화면에서 활동을 실행하면 새 활동 인스턴스가 만들어질 수 있습니다. 두 활동 다 동시에 재개됩니다.

다중 디스플레이에서 활동의 다중 인스턴스

그림 3. 다중 디스플레이에서 활동의 다중 인스턴스

Android 8.0에서 도입되었던 다중 디스플레이 API도 검토해볼 수 있습니다.

활동 및 애플리케이션 컨텍스트 비교

다중 디스플레이에서는 올바른 컨텍스트를 사용하는 것이 매우 중요합니다. 리소스에 액세스하는 경우 활동 컨텍스트(표시됨)와 애플리케이션 컨텍스트(표시되지 않음)가 서로 다릅니다.

활동 컨텍스트는 디스플레이 정보를 포함하며 활동이 표시되는 디스플레이 영역에 맞게 항상 조정됩니다. 이를 통해 현재 앱의 화면 밀도 또는 창 측정항목에 관한 올바른 정보를 얻을 수 있습니다. 현재 창 또는 디스플레이에 관한 정보를 얻으려면 항상 활동 컨텍스트(또는 다른 UI 기반 컨텍스트)를 사용해야 합니다. 활동 컨텍스트는 컨텍스트의 정보를 사용하는 일부 시스템 API(예: 토스트 메시지 개요 참고)에도 영향을 줍니다.

활동 창 구성 및 상위 디스플레이는 리소스 및 컨텍스트를 정의합니다. 다음과 같이 현재 디스플레이를 가져옵니다.

Kotlin

val activityDisplay = activity.getDisplay()

Java

Display activityDisplay = activity.getDisplay();

현재 활동 창 측정항목을 가져옵니다.

Kotlin

val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()

Java

WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();

현재 시스템 구성의 최대 창 측정항목을 가져옵니다.

Kotlin

val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()

Java

WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();

최대 창 측정항목은 계산하거나 레이아웃을 선택하거나 미리 가져올 리소스의 크기를 결정하는 데 사용됩니다. onCreate()에서 이 측정항목을 사용할 수 있으면 첫 번째 레이아웃 전달 전에 그러한 결정을 내릴 수 있습니다. 이 측정항목은 특정 뷰 요소를 배치하는 데 사용해서는 안 됩니다. 대신 Configuration 객체의 정보를 사용해야 합니다.

디스플레이 컷아웃

폴더블 기기가 접혔을 때와 펼쳐졌을 때 컷아웃 도형이 다를 수 있습니다. 컷아웃 문제가 발생하지 않도록 디스플레이 컷아웃 권장사항 지원을 읽어보세요.

보조 디스플레이

DisplayManager 시스템 서비스에서 사용 가능한 디스플레이를 가져올 수 있습니다.

Kotlin

val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = displayManager.getDisplays()

Java

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = displayManager.getDisplays();

Display 클래스를 사용하면 디스플레이 크기나 디스플레이가 안전한지 나타내는 플래그와 같은 특정 디스플레이 정보를 가져올 수 있습니다. 하지만 애플리케이션이 위치할 디스플레이 위치의 크기가 일정할 것이라고 가정해서는 안 됩니다. 멀티 윈도우 모드에서는 애플리케이션이 디스플레이의 일부를 차지하게 된다는 점을 기억하세요.

디스플레이에서 활동을 실행할 수 있는지 확인합니다.

Kotlin

val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)

Java

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent);

그런 다음 디스플레이에서 활동을 시작합니다.

Kotlin

val options = ActivityOptions.makeBasic()
options.setLaunchDisplayId(targetDisplay.displayId)
startActivity(intent, options.toBundle())

Java

ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(targetDisplay.displayId);
startActivity(intent, options.toBundle());

다중 디스플레이 지원

Android는 소프트웨어 키보드, 배경화면 및 런처에 다중 디스플레이 지원을 제공합니다.

소프트웨어 키보드

디스플레이가 시스템 데코레이션을 지원하도록 구성된 경우 키보드를 보조 화면에 표시할 수 있습니다. 디스플레이에서 텍스트 입력란이 입력을 요청하는 경우 자동으로 입력 방식 편집기(IME)가 표시됩니다.

보조 디스플레이의 키보드

그림 4. 보조 디스플레이의 키보드

배경화면

Android 10(API 수준 29)에서 보조 화면에 배경화면이 포함될 수 있습니다. 프레임워크는 각 디스플레이에 별도의 WallpaperService.Engine 인스턴스를 만듭니다. 각 엔진 표면이 독립적으로 그려져야 합니다. 개발자는 WallpaperService.Engine#getDisplayContext()에서 디스플레이 컨텍스트를 사용하여 에셋을 로드할 수 있습니다. 또한 WallpaperInfo.xml 파일이 android:supportsMultipleDisplays="true"로 설정되도록 해야 합니다.

스마트폰 및 보조 디스플레이의 배경화면

그림 5. 스마트폰 및 보조 디스플레이의 배경화면

런처

새로운 인텐트 필터 카테고리인 SECONDARY_HOME은 보조 화면에 전용 활동을 제공합니다. 활동의 인스턴스는 디스플레이마다 하나씩 시스템 데코레이션을 지원하는 모든 디스플레이에서 사용됩니다.

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

활동에는 다중 인스턴스를 방지하지 않고 다양한 화면 크기에 맞게 조정할 수 있는 시작 모드가 있어야 합니다. 시작 모드는 singleInstance 또는 singleTask가 될 수 없습니다.

예를 들어 Launcher3의 AOSP 구현은 SECONDARY_HOME 활동을 지원합니다.

스마트폰의 머티리얼 디자인 런처

그림 6. 스마트폰의 머티리얼 디자인 런처

보조 디스플레이의 머티리얼 디자인 런처

그림 7. 보조 디스플레이의 머티리얼 디자인 런처

윈도우 측정항목

Android 11(API 수준 30)에는 멀티 윈도우 모드에서 실행되는 앱의 경계를 제공하기 위해 다음 WindowManager 메서드가 도입되었습니다.

Jetpack WindowManager 라이브러리 메서드 computeCurrentWindowMetrics()computeMaximumWindowMetrics()는 각각 유사한 기능을 제공하며 이전 버전인 API 수준 14와 호환됩니다.

현재 디스플레이 외의 디스플레이에 관한 측정항목을 얻으려면 다음 단계를 따르세요.

  • 디스플레이 컨텍스트를 만듭니다.
  • 디스플레이의 창 컨텍스트를 만듭니다.
  • 창 컨텍스트의 WindowManager를 가져옵니다.
  • 앱에서 사용할 수 있는 최대 디스플레이 영역의 WindowMetrics를 가져옵니다.

Kotlin

val windowMetrics = context.createDisplayContext(display)
                    .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                    .getSystemService(WindowManager::class.java)
                    .maximumWindowMetrics

Java

WindowMetrics windowMetrics = context.createDisplayContext(display)
                              .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                              .getSystemService(WindowManager.class)
                              .getMaximumWindowMetrics();

지원 중단된 메서드

Display 메서드 getSize()getMetrics()가 API 수준 30에서 지원 중단되었으며 새로운 WindowManager 메서드로 대체되었습니다.

Android 12(API 수준 31)에서는 Display 메서드 getRealSize()getRealMetrics()를 지원 중단하고 이들의 동작을 업데이트하여 getMaximumWindowMetrics()의 동작과 더 근접하게 일치시킵니다.

멀티 윈도우 모드 구성

앱이 Android 7.0(API 수준 24) 이상을 타겟팅하는 경우 앱 활동이 멀티 윈도우 모드를 지원하는지 여부와 지원 방법을 설정할 수 있습니다. 매니페스트에서 속성을 설정하여 크기와 레이아웃을 모두 제어할 수 있습니다. 루트 활동의 속성 설정은 작업 스택 내의 모든 활동에 적용됩니다. 예를 들어, 루트 활동이 android:resizeableActivity="true"로 설정된 경우, 작업 스택에 있는 모든 활동의 크기를 조정할 수 있습니다. Chromebook과 같은 일부 큰 기기에서는 android:resizeableActivity="false"를 지정하더라도 앱이 크기 조절 가능한 창에서 실행될 수 있습니다. 이렇게 되면 앱이 중단되게 되는 경우, 필터를 사용하여 이러한 기기에 앱의 사용 가능 여부를 제한할 수 있습니다.

Android 12(API 수준 31)는 기본적으로 멀티 윈도우 모드로 설정되어 있습니다. 큰 화면(sw >= 600dp)에서는 모든 앱이 앱 구성과 관계없이 멀티 윈도우 모드로 실행됩니다. 작은 화면에서 시스템은 활동의 minWidth, minHeightresizeableActivity 설정을 통해 활동을 멀티 윈도우 모드에서 실행할 수 있는지 확인합니다.

resizeableActivity

매니페스트의 <activity> 또는 <application> 요소에서 이 속성을 설정하여 API 수준 30 이하에서 멀티 윈도우 모드를 사용 설정하거나 사용 중지할 수 있습니다.

<application
  android:name=".MyActivity"
  android:resizeableActivity=["true" | "false"] />

이 속성을 true로 설정하면, 활동을 화면 분할 모드와 자유 형식 모드로 시작할 수 있습니다. 이 속성을 false로 설정하면, 활동이 멀티 윈도우 모드를 지원하지 않습니다. 이 값이 false일 때 사용자가 멀티 윈도우 모드로 활동을 시작하려고 하면 활동은 전체 화면으로 열립니다.

앱이 API 수준 24 이상을 타겟팅하지만 이 속성 값을 지정하지 않은 경우 이 속성의 기본값은 true가 됩니다.

앱이 API 수준 31 이상을 타겟팅하는 경우 이 속성은 작은 화면 및 큰 화면에서 다르게 작동합니다.

  • 큰 화면(sw >= 600dp): 모든 앱이 멀티 윈도우 모드를 지원합니다. 이 속성은 활동의 크기를 조절할 수 있는지 여부를 나타냅니다. resizeableActivity="false"인 경우 디스플레이 치수를 준수하기 위해 필요한 경우 앱이 호환성 모드로 전환됩니다.
  • 작은 화면(sw < 600dp): resizeableActivity="true" 및 활동 최소 너비 및 최소 높이가 멀티 윈도우 요구사항 내에 있는 경우 활동은 멀티 윈도우 모드를 지원합니다. resizeableActivity="false"인 경우 활동이 최소 너비 및 높이와 관계없이 멀티 윈도우 모드를 지원하지 않습니다.

supportsPictureInPicture

이 속성을 매니페스트의 <activity> 노드에 설정하여 활동이 PIP 모드를 지원하는지 여부를 나타낼 수 있습니다.

<activity
  android:name=".MyActivity"
  android:supportsPictureInPicture=["true" | "false"] />

configChanges

멀티 윈도우 구성 변경사항을 직접 처리하려면(예: 사용자가 창 크기를 조절하는 경우) android:configChanges 속성을 앱 매니페스트 <activity> 노드에 추가하되 이 때 다음 값 이상을 사용합니다.

<activity
  android:name=".MyActivity"
  android:configChanges="screenSize | smallestScreenSize
      | screenLayout | orientation" />

android:configChanges을 추가하면 활동 및 프래그먼트는 소멸되어 다시 생성되는 대신에 onConfigurationChanged()의 콜백을 수신합니다. 그러면 필요에 따라 뷰를 수동으로 업데이트하고 리소스를 새로고침하고 기타 작업을 수행할 수 있습니다.

<layout>

Android 7.0 (API 수준 24) 이상에서 <layout> 매니페스트 요소는 멀티 윈도우 모드에서 활동이 동작하는 방식에 영향을 미치는 여러 속성을 지원합니다.

android:defaultWidth android:defaultHeight
자유 형식 모드에서 시작될 때 활동의 기본 높이 및 너비.
android:gravity
자유 형식 모드에서 시작될 때 활동의 초기 배치. 적합한 값은 Gravity를 참고하세요.
android:minWidth android:minHeight
화면 분할 및 자유 형식 모드에서 활동의 최소 높이 및 최소 너비. 사용자가 화면 분할 모드에서 구분선을 이동하여 활동을 지정된 최솟값보다 더 작게 만드는 경우, 시스템은 이 활동을 사용자가 요청한 크기로 자릅니다.

다음 코드에는 활동이 자유 형식 모드로 표시될 때 이 활동의 기본 크기와 위치 및 최소 크기를 지정하는 방법이 나와 있습니다.

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end|..."
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

런타임에 멀티 윈도우 모드

Android 7.0부터 시스템에서는 멀티 윈도우 모드로 실행할 수 있는 앱을 지원하는 기능을 제공합니다.

멀티 윈도우 모드에서 중지되는 기능

멀티 윈도우 모드에서 Android는 기기 화면을 다른 활동이나 앱과 공유하는 활동에 적용되지 않는 기능을 사용 중지하거나 무시할 수 있습니다.

또한 일부 시스템 UI 맞춤설정 옵션이 사용 중지됩니다. 예를 들어 앱이 멀티 윈도우 모드에서 실행되는 경우 상태 표시줄을 숨길 수 없습니다 (시스템 UI 공개 상태 제어 참고).

시스템에서 android:screenOrientation 속성 변경을 무시합니다.

멀티 윈도우 모드 쿼리 및 콜백

Activity 클래스는 멀티 윈도우 모드를 지원하는 다음 메서드를 제공합니다.

isInMultiWindowMode()
활동이 멀티 윈도우 모드에 있는지 나타냅니다.
isInPictureInPictureMode()

활동이 PIP 모드에 있는지 여부를 나타냅니다.

참고: PIP 모드는 멀티 윈도우 모드의 특별한 케이스입니다. myActivity.isInPictureInPictureMode()가 true를 반환하면 myActivity.isInMultiWindowMode()도 역시 true를 반환합니다.

onMultiWindowModeChanged()
시스템은 활동이 멀티 윈도우 모드로 들어가거나 이 모드에서 나올 때마다 이 메서드를 호출합니다. 시스템은 활동이 멀티 윈도우 모드로 들어갈 때는 true 값을 메서드에 전달하고, 활동이 멀티 윈도우 모드에서 나올 때는 false 값을 전달합니다.
onPictureInPictureModeChanged()
시스템은 활동이 PIP 모드로 들어가거나 이 모드에서 나올 때마다 이 메서드를 호출합니다. 시스템은 활동이 PIP 모드로 들어갈 때는 true 값을 메서드에 전달하고, 활동이 PIP에서 나올 때는 false 값을 전달합니다.

Fragment 클래스는 위와 같은 여러 메서드의 버전을 노출합니다(예: Fragment.onMultiWindowModeChanged()).

PIP 모드

활동을 PIP 모드에 두려면, enterPictureInPictureMode()를 호출합니다. 기기가 PIP 모드를 지원하지 않으면 이 메서드는 효과가 없습니다. 자세한 내용은 PIP 모드 지원을 참고하세요.

멀티 윈도우 모드에서 새 활동

새 활동을 실행할 때 가능하면 새 활동이 현재 활동 옆에 표시되어야 한다는 점을 나타낼 수 있습니다. 인텐트 플래그 FLAG_ACTIVITY_LAUNCH_ADJACENT는 인접한 창에 새 활동을 만들도록 시스템에 지시하기 때문에 두 활동이 화면을 공유하게 됩니다. 시스템에서는 가급적 이렇게 만들려고 하지만 반드시 보장되지는 않습니다.

기기가 자유 형식 모드에 있고 새 활동을 실행 중인 경우, ActivityOptions.setLaunchBounds()를 호출하여 이 새 활동의 치수와 화면 위치를 지정할 수 있습니다. 기기가 멀티 윈도우 모드에 있지 않으면, 이 메서드는 영향을 미치지 않습니다.

API 수준 30 이하에서 작업 스택 내에 활동을 실행하면 활동이 화면의 활동을 대체하여 모든 멀티 윈도우 속성을 상속합니다. 새 활동을 멀티 윈도우 모드에서 별도 창으로 시작하려면, 새 작업 스택에서 활동을 실행해야 합니다.

Android 12(API 수준 31)에서는 앱이 여러 활동 간에 애플리케이션의 작업 창을 분할할 수 있습니다. XML 구성 파일을 만들거나 Jetpack WindowManager API를 호출하여 앱이 활동을 표시하는 방식(전체 화면, 나란히 표시 또는 스택)을 결정합니다.

드래그 앤 드롭

사용자는 두 활동이 화면을 공유하는 동안 한 활동에서 다른 활동으로 데이터를 드래그 앤 드롭할 수 있습니다. Android 7.0 이전에는 사용자가 단일 활동 내에서만 데이터를 드래그 앤 드롭할 수 있었습니다. 드롭된 콘텐츠 허용을 빠르게 지원하려면 DropHelper API를 참고하세요. 포괄적인 드래그 앤 드롭 안내는 드래그 앤 드롭을 참고하세요.

멀티 인스턴스

각 루트 활동에는 별도의 프로세스에서 실행되며 자체 창에 표시되는 자체 작업이 있습니다. 별도의 창에서 앱의 새 인스턴스를 시작하려면 FLAG_ACTIVITY_NEW_TASK 플래그를 사용하여 새 활동을 시작하면 됩니다. 이를 멀티 윈도우 속성과 결합하여 새 창의 특정 위치를 요청할 수 있습니다. 예를 들어, 쇼핑 앱은 여러 개의 창을 표시하여 제품을 비교할 수 있습니다.

Android 12(API 수준 31)를 사용하면 동일한 작업 창에서 활동의 인스턴스 두 인스턴스를 나란히 실행할 수 있습니다.

사용자가 애플리케이션 런처 또는 작업 표시줄에서 다른 애플리케이션 인스턴스를 시작할 수 있게 하려면 런처 활동이 android:resizeableActivity="true"를 설정하고 여러 인스턴스를 방지하는 시작 모드를 사용하지 않는지 확인해야 합니다. 예를 들어 singleInstancePerTask 활동은 FLAG_ACTIVITY_MULTIPLE_TASK 또는 FLAG_ACTIVITY_NEW_DOCUMENT가 설정된 경우 서로 다른 작업에서 여러 번 인스턴스화될 수 있습니다.

멀티 인스턴스를 SlidingPaneLayout를 사용하는 멀티 패널 레이아웃(예: 단일 창 내에서 실행되는 목록 세부정보 프레젠테이션)과 혼동하지 마세요.

폴더블 기기에서 여러 인스턴스가 별도의 창에서 실행 중인 경우 상태가 변경되면 하나 이상의 인스턴스가 백그라운드로 전송될 수 있습니다. 예를 들어, 기기가 펼쳐져 있고 폴드의 양쪽에서 각각 창 하나당 앱 인스턴스 하나가 실행 중이라면 이 기기를 접을 경우 두 인스턴스의 창을 작은 화면에 맞추려고 시도하는 대신 인스턴스 중 하나가 종료될 수 있습니다.

멀티 윈도우 모드 확인

앱이 API 수준 24 이상을 타겟팅하는지에 관계없이, Android 7.0 이상을 실행 중인 기기에서 사용자가 앱을 멀티 윈도우 모드로 시작하려고 하면 앱이 멀티 윈도우 모드에서 어떻게 동작하는지 확인해야 합니다.

테스트 기기

Android 7.0(API 수준 24) 이상을 실행하는 기기는 멀티 윈도우 모드를 지원합니다.

API 수준 23 이하

사용자가 앱을 멀티 윈도우 모드에서 사용하려고 시도하는 경우, 이 앱이 고정 방향을 선언하지 않으면 시스템이 앱의 크기를 강제로 조정합니다.

앱이 고정 방향을 선언하지 않는 경우 Android 7.0 이상을 실행 중인 기기에서 앱을 시작해야 하며, 앱을 화면 분할 모드에 두도록 시도해야 합니다. 앱의 크기가 강제로 조정되는 경우 사용자 환경이 적절한지 확인하세요.

앱이 고정 방향을 선언하는 경우, 앱을 멀티 윈도우 모드에 두도록 해야 합니다. 이때 앱이 전체 화면 모드 상태에 있는지 확인하세요.

API 수준 24~30

앱이 API 수준 24~30을 타겟팅하고 멀티 윈도우 지원을 중지하지 않는 경우, 화면 분할 모드에서는 물론 자유 형식 모드에서도 다음 동작을 확인하세요.

  • 앱을 전체 화면 모드에서 시작한 다음, 최근 버튼을 길게 눌러서 멀티 윈도우 모드로 전환합니다. 앱이 적절히 전환되는지 확인합니다.
  • 앱을 멀티 윈도우 모드에서 직접 실행하고, 이 앱이 적절히 실행되는지 확인합니다. 멀티 윈도우 모드에서 앱을 실행하려면, 최근 버튼을 누르고 앱의 제목 표시줄을 길게 누른 다음 화면의 강조표시된 영역 중 하나로 제목 표시줄을 끌어서 놓습니다.
  • 화면 분할선을 드래그하여 화면 분할 모드에서 앱의 크기를 조정합니다. 작동 중단 없이 앱 크기가 조정되는지 확인하고, 필요한 UI 요소가 표시되는지 확인합니다.
  • 앱에 최소 치수를 지정한 경우, 이 치수 아래로 앱 크기를 조정해 봅니다. 지정된 최소 치수보다 더 작게 앱 크기를 조정할 수 없는지 확인합니다.
  • 모든 테스트를 통해 앱의 성능이 적절한지 확인합니다. 예를 들어, 앱 크기를 조정한 후 UI를 업데이트하기에 지연이 너무 길지 않은지 확인합니다.

API 수준 31 이상

앱이 API 수준 31 이상을 타겟팅하고 기본 활동의 최소 너비와 최소 높이가 사용 가능한 디스플레이 영역의 각 크기보다 작거나 같다면 API 수준 24~30에 나열된 모든 동작을 확인하세요.

테스트 체크리스트

멀티 윈도우 모드에서 앱의 성능을 확인하려면, 다음 작업을 시도해 보세요. 별다른 설명이 없다면 화면 분할 및 자유 형식 모드에서 모두 이 작업을 시도해야 합니다.

  • 다중 창 모드에 들어갔다 나옵니다.
  • 사용 중인 앱에서 다른 앱으로 전환해 보고, 앱이 표시는 되지만 활성 상태가 아닐 때 적절히 동작하는지 확인합니다. 예를 들어 앱이 동영상을 재생 중인 경우, 사용자가 다른 앱과 상호작용하는 동안에 이 동영상이 계속 재생되는지 확인합니다.
  • 화면 분할 모드에서 화면 분할선을 이동하여 앱을 크고 작게 바꾸어 봅니다. 앱을 나란히 또는 상하로 놓은 구성에서 이 작업을 시도해 봅니다. 앱이 비정상적으로 종료되지 않는지, 필수 기능이 표시되는지, 그리고 크기 조정 작업이 너무 오래 걸리지 않는지 확인합니다.
  • 빠르게 연속해서 여러 가지 크기 조정 작업을 수행합니다. 앱이 비정상적으로 종료되지 않는지 또는 메모리가 누수되지 않는지 확인합니다. Android 스튜디오의 메모리 프로파일러는 앱의 메모리 사용량에 관한 정보를 제공합니다(메모리 프로파일러를 사용하여 앱의 메모리 사용량 검사 참고).
  • 여러 가지 다른 창 구성에서 앱을 평소처럼 사용하며 이 앱이 제대로 작동하는지 확인합니다. 텍스트를 읽을 수 있는지 확인하고, 해당 UI 요소가 상호작용하기에 너무 작지 않은지 확인합니다.

멀티 윈도우 지원 사용 중지됨

API 수준 24~30에서 android:resizeableActivity="false"를 설정하여 멀티 윈도우 지원을 사용 중지한 경우 Android 7.0~11을 실행하는 기기에서 앱을 실행하고 앱을 화면 분할 및 자유 형식 모드로 전환해야 합니다. 이때 앱이 전체 화면 모드에 상태에 있는지 확인하세요.

추가 리소스

Android의 멀티 윈도우 지원에 관한 자세한 내용은 다음을 참고하세요.