홈으로 돌아가기

Android 4.2+에서 DreamService와 Compose

DreamService는 충전 중 Android 슬립 모드에서 UI를 생성할 수 있게 합니다. Jetpack Compose를 통합하려면 LifecycleOwner와 SavedStateRegistryOwner를 구현해야 합니다. 중/시니어 개발자를 위한 코드가 포함된 단계별 가이드.

DreamService에서 Compose: 잠자는 Android를 위한 UI
Advertisement 728x90

안드로이드 DreamService: 드림 스크린을 위한 Jetpack Compose 통합

안드로이드 4.2 에서 도입된 DreamService 는 기기가 충전 중이고 대기 상태일 때 커스텀 UI 를 표시할 수 있게 해줍니다. 이 컴포넌트는 Service 를 상속받으며 버튼을 포함한 인터랙티브 요소를 지원합니다. 활성화하려면 디스플레이 설정에서 사용자가 수동으로 구성해야 합니다. 이 솔루션은 메인 앱 라이프사이클에 영향을 주지 않고 동적 스크린을 만드는 데 적합합니다.

AndroidManifest.xml 에 서비스를 선언하는 것은 표준적입니다:

<service
    android:name=".MyDreamService"
    android:exported="true"
    android:description="@string/dream_service_description"
    android:icon="@drawable/dream_service_icon"
    android:label="@string/dream_service_label"
    android:permission="android.permission.BIND_DREAM_SERVICE">

    <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

기본 구현은 뷰를 구성하기 위해 onAttachedToWindow() 를 사용합니다:

Google AdInline article slot
class MyDreamService : DreamService() {

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()

        isInteractive = false
        isFullscreen = true
        setContentView(R.layout.dream_service_layout)
    }
}

DreamService 에 Jetpack Compose 통합하기

setContentView 메서드는 Views 와만 작동하므로 Compose 를 위해 ComposeView 를 생성합니다. 그러나 DreamService 는 Compose 가 올바르게 작동하는 데 중요한 ViewTreeLifecycleOwnerSavedStateRegistryOwner 를 제공하지 않습니다.

해결책은 SavedStateRegistryOwner 구현으로 DreamService 를 확장하는 것입니다:

class MyDreamService : DreamService(), SavedStateRegistryOwner {

    private val lifecycleRegistry = LifecycleRegistry(this)
    private val savedStateRegistryController = SavedStateRegistryController.create(this)

    override val lifecycle: Lifecycle
        get() = lifecycleRegistry

    override val savedStateRegistry: SavedStateRegistry
        get() = savedStateRegistryController.savedStateRegistry
}

onAttachedToWindow() 에서 라이프사이클과 레지스트리를 동기화합니다:

Google AdInline article slot
val composeView = ComposeView(this).apply {
    setViewTreeLifecycleOwner(this@MyDreamService)
    setViewTreeSavedStateRegistryOwner(this@MyDreamService)
    setContent {
        DreamServiceTheme {
            DreamScreen(
                onOpenSettings = { 
                    openSettingsAndExitDream() 
                }
            )
        }
    }
}

setContentView(composeView)

적절한 상태 동기화를 위해 DreamService 콜백 (onAttachedToWindow, onDetachedFromWindow 등) 에서 lifecycle 메서드를 호출하는 것을 잊지 마세요.

주요 제한 사항 및 모범 사례

  • 활성화: 사용자가 설정에서 Daydream 을 수동으로 활성화해야 합니다. 자동 실행은 불가능합니다.
  • 라이프사이클: Compose 를 위해 LifecycleOwner 를 완전히 구현하세요. 그렇지 않으면 UI 가 업데이트되지 않습니다.
  • 성능: 기기가 절전 모드이므로 무거운 애니메이션은 피하세요.
  • 상호작용: isInteractive = true 는 버튼을 허용하지만 전력 소비에 대해 주의가 필요합니다.

구현 단계 목록:

  • 매니페스트에 BIND_DREAM_SERVICE 권한으로 서비스를 선언합니다.
  • DreamService 를 상속받고 SavedStateRegistryOwner 를 추가합니다.
  • LifecycleRegistrySavedStateRegistryController 를 초기화합니다.
  • ComposeView 에서 setContent 전에 소유자를 설정합니다.
  • 충전 모드에서 실제 기기에서 테스트합니다.

주요 요약

  • DreamService 는 라이프사이클 조정 후 Compose 를 지원하는 Activity 외의 완전한 UI 호스터입니다.
  • 디스플레이 설정에서 수동 활성화는 필수입니다.
  • 서비스를 확장하여 ViewTreeLifecycleOwner 문제를 해결하세요.
  • 시계, 알림, 미니 게임 등 대기 화면에 적합합니다.
  • 전력 절약이 중요합니다. 드로우 호출을 최소화하세요.

이 기능은 안드로이드 개발 기능을 확장하여 비표준 시나리오에서 기기 동작을 커스터마이징할 수 있게 합니다. 시니어 개발자에게는 플랫폼 서비스와 현대 UI 프레임워크의 통합에 대한 깊은 이해의 맥락에서 유용합니다.

Google AdInline article slot

— Editorial Team

Advertisement 728x90

다음 읽기