返回首页

Android 4.2+ 中的 DreamService 和 Compose

DreamService 允许在 Android 充电时的睡眠模式下创建 UI。集成 Jetpack Compose 需要实现 LifecycleOwner 和 SavedStateRegistryOwner。适用于中高级开发者的带代码分步指南。

DreamService 中的 Compose:沉睡 Android 的 UI
Advertisement 728x90

Android 中的 DreamService:为屏保屏幕集成 Jetpack Compose

DreamService 自 Android 4.2 引入,允许在设备充电闲置时显示自定义 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)
    }
}

将 Jetpack Compose 集成到 DreamService

setContentView 方法仅适用于 Views,因此需要为 Compose 创建 ComposeView。然而,DreamService 不提供 ViewTreeLifecycleOwnerSavedStateRegistryOwner,而这对于 Compose 正常运行至关重要。

解决方案是扩展 DreamService 以实现 SavedStateRegistryOwner

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 回调(onAttachedToWindowonDetachedFromWindow 等)中调用 lifecycle 方法,以确保状态正确同步。

关键限制与最佳实践

  • 激活:用户必须在设置中手动启用屏保功能。无法自动启动。
  • 生命周期:确保为 Compose 完整实现 LifecycleOwner,否则 UI 将不会更新。
  • 性能:避免繁重的动画——设备处于休眠模式。
  • 交互性isInteractive = true 允许使用按钮,但需谨慎对待功耗。

实施步骤列表:

  • 在清单中使用 BIND_DREAM_SERVICE 权限声明服务。
  • 继承 DreamService 并添加 SavedStateRegistryOwner
  • 初始化 LifecycleRegistrySavedStateRegistryController
  • ComposeView 中,于 setContent 之前设置所有者。
  • 在充电模式下于真实设备测试。

核心要点

  • DreamService 是 Activity 之外的完整 UI 宿主,经过生命周期调整后支持 Compose。
  • 必须在显示设置中手动激活。
  • 通过扩展服务解决 ViewTreeLifecycleOwner 问题。
  • 适用于闲置屏幕:时钟、通知、迷你游戏。
  • 省电至关重要——最小化绘制调用。

此功能扩展了 Android 开发能力,允许在非标准场景中定制设备行为。对于高级开发者而言,有助于深入理解平台服务及其与现代 UI 框架的集成。

Google AdInline article slot

— Editorial Team

Advertisement 728x90

继续阅读