Volver al inicio

DreamService y Compose en Android 4.2+

DreamService permite crear UI en modo de suspensión de Android mientras se carga. Integrar Jetpack Compose requiere implementar LifecycleOwner y SavedStateRegistryOwner. Guía paso a paso con código para desarrolladores intermedios/senior.

Compose en DreamService: UI para Android en suspensión
Advertisement 728x90

DreamService en Android: Integración de Jetpack Compose para Pantallas de Sueño

DreamService, introducido en Android 4.2, permite mostrar una interfaz personalizada en el dispositivo mientras está inactivo durante la carga. El componente hereda de Service y admite elementos interactivos, incluidos botones. La activación requiere configuración manual del usuario en los ajustes de pantalla. Esta solución es adecuada para crear pantallas dinámicas sin afectar el ciclo de vida principal de la aplicación.

Declarar el servicio en AndroidManifest.xml es estándar:

<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>

La implementación básica usa onAttachedToWindow() para configurar la vista:

Google AdInline article slot
class MyDreamService : DreamService() {

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()

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

Integración de Jetpack Compose en DreamService

El método setContentView solo funciona con Views, por lo que se crea un ComposeView para Compose. Sin embargo, DreamService no proporciona ViewTreeLifecycleOwner ni SavedStateRegistryOwner, que son críticos para que Compose funcione correctamente.

La solución es extender DreamService con una implementación de 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
}

En onAttachedToWindow(), sincroniza el lifecycle y el registro:

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

setContentView(composeView)

No olvides llamar a los métodos lifecycle en los callbacks de DreamService (onAttachedToWindow, onDetachedFromWindow, etc.) para una sincronización adecuada del estado.

Limitaciones Clave y Mejores Prácticas

  • Activación: Los usuarios deben habilitar Daydream manualmente en los ajustes. El lanzamiento automático es imposible.
  • Lifecycle: Asegura la implementación completa de LifecycleOwner para Compose, de lo contrario la UI no se actualizará.
  • Rendimiento: Evita animaciones pesadas; el dispositivo está en modo reposo.
  • Interactividad: isInteractive = true permite botones, pero requiere precaución respecto al consumo de energía.

Lista de pasos de implementación:

  • Declara el servicio en el manifiesto con el permiso BIND_DREAM_SERVICE.
  • Hereda de DreamService y añade SavedStateRegistryOwner.
  • Inicializa LifecycleRegistry y SavedStateRegistryController.
  • En ComposeView, establece los propietarios antes de setContent.
  • Prueba en un dispositivo real en modo de carga.

Conclusiones Clave

  • DreamService es un anfitrión de UI completo además de Activity, admitiendo Compose tras ajustes de lifecycle.
  • La activación manual en los ajustes de pantalla es obligatoria.
  • Resuelve los problemas de ViewTreeLifecycleOwner extendiendo el servicio.
  • Adecuado para pantallas inactivas: relojes, notificaciones, minijuegos.
  • El ahorro de energía es crítico: minimiza las llamadas de dibujo.

Esta función expande las capacidades de desarrollo en Android, permitiendo personalizar el comportamiento del dispositivo en escenarios no estándar. Para desarrolladores senior, es útil en el contexto de una comprensión profunda de los servicios de plataforma y su integración con frameworks de UI modernos.

Google AdInline article slot

— Editorial Team

Advertisement 728x90

Leer después