Cómo optimizar las caras de reloj

La cara de reloj de Wear OS funciona continuamente, por lo que debe usar la energía de manera eficiente.

Además, se debe optimizar el rendimiento de la cara de reloj. Los servicios no deben realizar procesamientos innecesarios. Las caras de reloj con animaciones deben ejecutarse sin problemas y, al mismo tiempo, mostrar notificaciones e indicadores del sistema.

Optimización básica

En esta sección se explican las prácticas recomendadas para mejorar la eficiencia.

Color y brillo de la cara de reloj

Los colores oscuros conservan la batería de un reloj. Las siguientes son recomendaciones para establecer el fondo de la cara de reloj y, así, optimizar su uso de la batería:

  • Color. Siempre que sea posible, usa un fondo negro.
  • Brillo. Cuando los requisitos de la cara de reloj no permiten el uso de un fondo negro, debes tratar de mantener el brillo del color de fondo en 25% o menos en una escala HSV (matiz, saturación, valor) o HSB. Por ejemplo, si usas la clase Color para establecer el color de fondo y defines el color con la escala HSV, deberías usar 25 o menos para la configuración del valor (es decir, para la configuración del brillo).

Usa devoluciones de llamada en WatchFaceService.Engine

Asegúrate de que la cara de reloj realice procesamientos solo cuando esté activa; usa devoluciones de llamada en WatchFaceService.Engine. Preferentemente, usa los siguientes métodos de esa clase para determinar si la cara de reloj es visible:

  • onVisibilityChanged(boolean)
  • isVisible()

Otra opción es usar los siguientes métodos de la misma clase (WatchFaceService.Engine):

  • onCreate()
  • onDestroy()

Usa objetos de escucha registrados con la interfaz DataClient

Para escuchar eventos, usa objetos de escucha activos que estén registrados con DataClient.addListener. Para ver un ejemplo, consulta Cómo sincronizar elementos de datos.

No uses WearableListenerService para escuchar eventos, ya que se llama sin importar si una cara de reloj está activa o no. Para obtener más información, consulta Baja de BIND_LISTENER.

No registres un receptor de emisión en el archivo de manifiesto de Android para obtener eventos del sistema, como cambios de zona horaria, eventos de batería, etc., porque se llama a BroadcastReceiver sin importar si la cara de reloj está activa o no. Sin embargo, puedes usar el método registerReceiver de la clase de Context para registrar un receptor.

Usa capacidades dinámicas para interactuar con el teléfono

Cuando una cara de reloj requiere que se ejecute una operación en el teléfono, ese código solo debe ejecutarse cuando la cara de reloj está activa. El método recomendado para permitir que la app en el teléfono detecte que la cara de reloj correspondiente está activa es usar la API de CapabilityClient.

Define una capacidad que se agregue de manera dinámica en el método onCreate() de WatchFaceService.Engine. Quita la capacidad con el método onDestroy().

Por ejemplo, una app que busca datos periódicos para mostrar en la cara de reloj debe registrar un objeto de escucha para las capacidades anunciadas por la cara de reloj. Agrega una alarma para obtener datos actualizados y enviarlos a la cara de reloj cuando esté disponible. Quita la alarma periódica si la cara de reloj ya no está seleccionada o el reloj está fuera de alcance, se apagó o no puede recibir actualizaciones por otra razón.

Supervisa el consumo de energía

La aplicación complementaria de Wear OS permite a los desarrolladores y usuarios ver cuánta batería consumen los diferentes procesos en el dispositivo wearable (en Configuración > Batería del reloj).

Para obtener información sobre las características de Android 5.0 que te ayudan a mejorar la duración de la batería, consulta el Proyecto Volta.

Registra caras de reloj con reconocimiento de encriptación

Android 7.0 y versiones posteriores admiten encriptación basada en archivos y permiten que las aplicaciones con reconocimiento de encriptación se ejecuten antes de que el usuario proporcione la contraseña de desencriptación en el inicio. Esto puede reducir la duración de la transición de la animación de inicio a la cara de reloj hasta 30 segundos.

Para habilitar un inicio más rápido, agrega android:directBootAware="true" al manifiesto de la cara de reloj.

Nota: Usa esta función con caras de reloj que no utilicen almacenamiento encriptado con credenciales.

Prácticas recomendadas para animaciones

Las prácticas recomendadas en esta sección ayudan a reducir el consumo de energía de las animaciones.

Reduce la velocidad de fotogramas de las animaciones

A menudo, el procesamiento de las animaciones consume una cantidad considerable de energía. La mayoría de las animaciones tienen un aspecto fluido a 30 fotogramas por segundo, por lo que deberías evitar ejecutar tus animaciones a una velocidad de fotogramas más alta. Puedes controlar la velocidad de fotogramas cuando se utiliza invalidate() al final del método draw(). Para ello, agrega una demora antes de llamar al método invalidate(). Descubre cómo implementar este paso en Cómo dibujar caras de reloj.

Deja que la CPU se suspenda entre animaciones

Las animaciones y los cambios pequeños en el contenido de la cara de reloj activan la CPU. La cara de reloj debe dejar que la CPU se suspenda entre animaciones. Por ejemplo, puedes usar breves ráfagas de animación cada un segundo en modo interactivo y luego dejar que la CPU se suspenda hasta el siguiente segundo. Dejar que la CPU se suspenda a menudo, aunque sea de manera breve, puede reducir considerablemente el consumo de energía.

Para maximizar la duración de la batería, usa animaciones con moderación. Incluso los dos puntos intermitentes despiertan la CPU con cada parpadeo y perjudican la duración de la batería.

Reduce el tamaño de tus elementos de mapas de bits

Muchas caras de reloj constan de una imagen de fondo y otros recursos gráficos que se transforman y se superponen sobre la imagen de fondo, como las agujas del reloj y otros elementos del diseño que se mueven con el tiempo. Por lo general, esos elementos gráficos se rotan (y, a veces, se ajustan) dentro del método Engine.onDraw() cada vez que el sistema vuelve a dibujar la cara de reloj, como se describe en Cómo dibujar la cara de reloj.

Cuanto más grandes son estos recursos gráficos, más complejo es el procesamiento necesario para transformarlos. La transformación de grandes recursos gráficos en el método Engine.onDraw() reduce de manera drástica la velocidad de fotogramas a la que el sistema puede ejecutar tus animaciones.

Figura 1: Las agujas del reloj se pueden recortar para quitar píxeles adicionales.

Para mejorar el rendimiento de la cara de reloj, haz lo siguiente:

  • No uses elementos gráficos que sean más grandes de lo que necesitas.
  • Quita píxeles transparentes adicionales alrededor de los bordes.

Se puede reducir la aguja del reloj de ejemplo en el lado izquierdo de la figura 1 en un 97%.

Reducir el tamaño de los elementos de mapa de bits como se describe en esta sección no solo mejora el rendimiento de las animaciones, sino que también ahorra energía.

Combina elementos de mapas de bits

Si tienes mapas de bits que a menudo se dibujan juntos, considera combinarlos en el mismo recurso gráfico. A menudo, es posible combinar la imagen de fondo en modo interactivo con las marcas de verificación para evitar dibujar dos mapas de bits de pantalla completa cada vez que el sistema vuelve a dibujar la cara de reloj.

Inhabilita el suavizado de contorno al dibujar mapas de bits ajustados

Cuando dibujas un mapa de bits ajustado en el objeto Canvas utilizando el método Canvas.drawBitmap(), puedes proporcionar una instancia Paint para configurar varias opciones. Para mejorar el rendimiento, inhabilita el suavizado de contorno mediante el método setAntiAlias(), ya que esta opción no tiene ningún efecto en los mapas de bits.

Figura 2: Ejemplo de filtro de mapa de bits inhabilitado (izquierda) y habilitado (derecha).

Usa el filtro de mapa de bits

Para los elementos de mapas de bits que dibujas sobre otros elementos, habilita el filtro de mapas de bits en la misma instancia Paint utilizando el método setFilterBitmap(). En la figura 2, se muestra una vista ampliada de una aguja de reloj con filtro de mapa de bits y sin él.

Nota: En el modo ambiente de pocos bits, el sistema no procesa de manera confiable los colores en la imagen para que el filtro de mapas de bits lo procese correctamente. Cuando el modo ambiente está activo, inhabilita el filtro de mapa de bits.

Traslada las operaciones intensivas fuera del método de dibujo

El sistema llama al método Engine.onDraw() cada vez que vuelve a dibujar la cara de reloj, por lo que solo deberías incluir las operaciones que son estrictamente necesarias para actualizar la cara de reloj dentro de este método a fin de mejorar el rendimiento.

Cuando sea posible, evita realizar las siguientes operaciones dentro del método Engine.onDraw():

  • Carga de imágenes y otros recursos
  • Cambio del tamaño de las imágenes
  • Asignación de objetos
  • Procesamientos cuyos resultados no cambian entre marcos

Por lo general, puedes realizar esas operaciones en el método Engine.onCreate() en su lugar. Puedes cambiar el tamaño de las imágenes de manera anticipada en el método Engine.onSurfaceChanged(), que te proporciona el tamaño del lienzo.

Para analizar el rendimiento de la cara de reloj, usa el Generador de perfiles de CPU. En especial, asegúrate de que el tiempo de ejecución de la implementación de Engine.onDraw() sea corto y coherente en todas las invocaciones. Para obtener más información, consulta Cómo registrar e inspeccionar seguimientos de métodos.