Necesito mostrar en la pantalla del teléfono información técnica sobre su condición, más precisamente, sobre su condición en el grupo de prueba. Siempre quiero ver esta información, es decir, en la pantalla de inicio y sin movimientos corporales adicionales.
Solo hay dos formas que no afectarán la ejecución de otras aplicaciones: Widget o Live wallpaper. Elegí Live wallpaper, también son "fondos de pantalla en vivo", ya que automáticamente llegan a todas las páginas de la pantalla de inicio, e incluso a la pantalla de bloqueo. Este artículo proporciona consejos prácticos sobre cómo crear fondos de pantalla en vivo.
En busca de la verdad
Documentación sobre el gato "live wallpaper" lloró. Desde el primer (y único) anuncio en el blog que ocurrió hace más de 9 años, Google no ha hecho un solo ejemplo inteligible o codelab sobre este tema. Tenía que entenderlo.
Primeros fundamentos. La mecánica interna de Android es tal que solo podemos instalar la aplicación en el dispositivo, y el dispositivo de todas las aplicaciones es el mismo. Dado que "fondo de pantalla en vivo" también es una aplicación, la elección de un componente de control no es excelente, y debemos esperar que sea Servicio. Encontrarlo es fácil: es WallpaperService .
Puede haber varias instancias de "fondo de pantalla en vivo", y su ciclo de vida será diferente al de Actividad o Vista. En consecuencia, debería haber una clase base más. Este es WallpaperService.Engine (¡y es necesariamente interno para WallpaperService !). Si observa de cerca, resultará ser el mismo proveedor de eventos del ciclo de vida que Actividad, Servicio y otros similares.
El ciclo de vida del "fondo de pantalla animado" se ve así:
onCreate (SurfaceHolder surfaceHolder)
onSurfaceCreated (titular de SurfaceHolder)
onSurfaceChanged (soporte SurfaceHolder, formato int, ancho int, altura int)
onVisibilityChanged (boolean visible)
onSurfaceRedrawNeeded (titular de SurfaceHolder)
onSurfaceDestroyed (soporte SurfaceHolder)
onDestroy ()
De esta lista queda claro cuándo puede / necesita volver a dibujar la imagen (o comenzar a volver a dibujarla si tiene animación), y cuándo es el momento de detener toda actividad y no gastar batería.
El método onSurfaceRedrawNeeded () se destaca del resto, lea a continuación. También hay un método isVisible () para ayudar (que en Kotlin se convierte en la propiedad isVisible
).
Ahora puedes construir este constructor. Comenzaré desde el final.
Dibujar
Tendremos que dibujar sobre lienzo , no tendremos ningún diseño e inflador. Cómo obtener Canvas desde SurfaceHolder y cómo dibujarlo está más allá del alcance de este artículo, hay un ejemplo simple a continuación.
fun dummyDraw(c: Canvas) { c.save() c.drawColor(Color.CYAN) c.restore() }
Métodos del ciclo de vida del motor
Todos los métodos de ciclo de vida excepto onSurfaceRedrawNeeded
no requieren un onSurfaceRedrawNeeded
inmediato. Por lo tanto, un buen tono sería volver a dibujar la cola.
override fun onSurfaceCreated(holder: SurfaceHolder?) { super.onSurfaceCreated(holder) redrawHandler.planRedraw() } override fun onSurfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) { super.onSurfaceChanged(holder, format, width, height) redrawHandler.planRedraw() } override fun onVisibilityChanged(visible: Boolean) { super.onVisibilityChanged(visible) redrawHandler.planRedraw() } override fun onSurfaceDestroyed(holder: SurfaceHolder?) { super.onSurfaceDestroyed(holder) redrawHandler.omitRedraw() } override fun onDestroy() { super.onDestroy() redrawHandler.omitRedraw() } override fun onSurfaceRedrawNeeded(holder: SurfaceHolder) { super.onSurfaceRedrawNeeded(holder) redrawHandler.omitRedraw() drawSynchronously(holder)
Preste atención a onSurfaceRedrawNeeded , que nos llama a la devolución de llamada SurfaceHolder del mismo nombre , que ocurre al cambiar el tamaño y eventos similares. Esta devolución de llamada le permite volver a dibujar inmediatamente, sin permitir que el usuario muestre la imagen anterior (y ya incorrecta). El sistema garantiza que hasta que se produzca un retorno de este método, la salida a la pantalla se pausará.
Programador
Me gusta redefinir Handler y no ejecutar Runnable en él. En mi opinión, muy elegante.
En caso de que tenga animación o actualizaciones periódicas, deberá hacer una cola regular del mensaje ( postAtTime () y postDelayed () para ayudarlo). Si los datos se actualizan esporádicamente, solo llame a planRedraw()
para actualizarlos.
val redrawHandler = RedrawHandler() inner class RedrawHandler : Handler(Looper.getMainLooper()) { private val redraw = 1 fun omitRedraw() { removeMessages(redraw) } fun planRedraw() { omitRedraw() sendEmptyMessage(redraw) } override fun handleMessage(msg: Message) { when (msg.what) { redraw -> drawSynchronously() else -> super.handleMessage(msg) } } }
Servicio y motor
Esta mareshka de Service and Engine se ensambla así:
class FooBarWallpaperService : WallpaperService() { override fun onCreateEngine() = FooBarEngine() inner class FooBarEngine : Engine() { .... } }
AndroidManifest y otros hechizos
Llamo hechizos en el desarrollo de software que es imposible de entender, pero es necesario repetir exactamente.
En .../app/src/main/res/xml
debe haber un archivo XML con una descripción de "fondo de pantalla en vivo". El nombre de este archivo debe especificarse en AndroidManifest (busque la palabra foobarwallpaper
en el ejemplo a continuación)
<?xml version="1.0" encoding="UTF-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@drawable/some_drawable_preview" android:description="@string/wallpaper_description" />
No pierda permission
, meta-data
y intent-filter
en la descripción del Servicio:
<service android:name=".FooBarWallpaperService" android:enabled="true" android:label="Wallpaper Example" android:permission="android.permission.BIND_WALLPAPER"> <meta-data android:name="android.service.wallpaper" android:resource="@xml/foobarwallpaper" > </meta-data> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService"> </action> </intent-filter> </service>
Cómo agregar
Los "fondos de pantalla en vivo" se esconden, por lo tanto, una pista. Describo cómo se ve en mi Samsung.
Para comenzar, mantenga presionado en algún lugar de la pantalla de inicio, el teléfono entrará en el modo de configuración del escritorio, aparecerá el icono de Fondos de pantalla .
Hacemos clic en el ícono Fondos de pantalla , varias secciones, necesitamos Mis fondos de pantalla , hacemos clic en la inscripción Ver todo en la esquina superior derecha de la sección, la lista se abre en pantalla completa.
Presionamos los "tres puntos" de la llamada del menú, en él el elemento de fondos de pantalla VIVOS (tengo uno), aparece una lista de "fondos de pantalla animados " disponibles.
Seleccione nuestro fondo de pantalla y seleccione "Pantalla de inicio y bloqueo".
Aparecerá una "vista previa", que ya está siendo dibujada por nuestra aplicación (para reconocer este momento, existe el método isPreview () ), haga clic en Establecer como fondo de pantalla ... Y no vemos nada, porque volvemos a la lista de fondos de pantalla disponibles.
Haz clic en "Inicio" y disfruta.
¿Y luego Android Watch?
Una observación interesante en el camino es que las caras en Android Watch se hacen exactamente de la misma manera (con la precisión de que tienen sus propias clases base con su propia implementación): el mismo Servicio + Motor , casi los mismos metadatos y filtro de intención para el Servicio en el manifiesto (en que la palabra fondo de pantalla aparece cuatro veces :), también debe escribir su propio sheduler basado en Handler .
En las clases base de Watch Faces hay un onDraw()
listo para onDraw()
, a donde se pasa Canvas y hay invalidate()
para llamarlo. Pero esta no es una diferencia fundamental, sino la parte implementada de la repetitiva.
A diferencia de Live Wallpaper, hay ejemplos de Watch Faces, puede profundizar en ellos (enlaces aquí , al principio).
Que paso
Las capturas de pantalla de una aplicación que pinta una pantalla verde no tienen mucho sentido. Pero un par de fotos que se basaron en esto se hicieron para el puesto de combate, debajo del spoiler.
Un par de fotos

Las pegatinas son el sistema de detección de problemas restante de la generación anterior.
Agradecimientos
Si no fuera por estos dos artículos, habría vagado en la oscuridad mucho más tiempo. ¡No puedo imaginar cómo podrían haberse escrito ya en 2010 con tanta documentación de calidad?
Kirill Grouchnikov, fondos de pantalla animados
Vogella, Android Live Wallpaper - Tutorial
Código fuente
→ GitHub