Analytics es una parte integral de una aplicación móvil moderna. Analytics le permite recopilar información sobre el usuario para desarrollar y mejorar el producto.
A menudo, la recopilación de información reduce el rendimiento de la aplicación. El proceso carga adicionalmente la CPU y la memoria, y este es un precio alto. El funcionamiento lento de la aplicación puede causar críticas negativas de los usuarios, disminuir la calificación y conducir a la pérdida de audiencia.
Nuestro equipo de desarrolladores de Android se enfrentó a este problema mientras trabajaba en el próximo proyecto, que estaba relacionado con las noticias. Tuvimos que registrar la visualización de cada noticia en la lista.
Intento número 1
Habiendo recibido la tarea de recopilar análisis, el equipo mostró rápidamente el resultado. El desencadenante para generar un evento fue el método
onViewAttachedToWindow . Todo parece estar bien, pero con un desplazamiento rápido, la interfaz se colgó notablemente, algo salió mal. El problema tuvo que ser resuelto.
Todos perciben la suspensión de manera diferente, por lo que necesitábamos hechos y pruebas. Para medir el retraso, se eligió FPS (cuadros por segundo) y
TinyDenser de FPS-meter para medir el
retraso . Después de conectar la utilidad, el equipo recibió una confirmación objetiva del problema: el indicador cayó, a veces de manera bastante notable: menos de 30 fotogramas por segundo, la grabación de pantalla con la utilidad activada se muestra en la Figura 1.
Figura 1. Grabación de pantalla antes de la optimizaciónIntento número 2
¿Y si pospone el envío de eventos hasta que el usuario se desplace por la lista? Hmmm, pensó el equipo, y decidió crear una cola de eventos y enviarlos después de que el desplazamiento se detenga. Aquí todo es simple: agregamos
OnScrollListener al
RecyclerView y esperamos hasta que el nuevo
Estado sea plano
SCROLL_STATE_IDLE : el problema está parcialmente resuelto.
class IdleStateScrollListener(private val analyticsFacade: AnalyticsFacade) : RecyclerView.OnScrollListener() { fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { analyticsFacade.setPending(newState != RecyclerView.SCROLL_STATE_IDLE) } }
El siguiente paso es implementar la acumulación de eventos y su envío.
Para administrar la cola, creamos una clase responsable de agregar eventos a la cola y enviar análisis al servicio. Para el envío periódico, elegimos un servicio
ScheduledExecutorService con un hilo que ejecutaba
Runnable cada segundo, la hora se seleccionó empíricamente.
Esto arrojó resultados inmediatamente, un aumento significativo en FPS. En principio, el problema se resolvió, en la Figura 2 vemos el resultado de la aplicación después del segundo intento. Pero solo había una tarea: los eventos se enviaban al servicio, lo que conducía a la generación frecuente de objetos de la clase
Intent , y esto además cargaba el
GC y entregaba "cosas agradables" en forma de pausas para
detener el mundo .
Figura 2. Grabación de pantalla después del segundo intentoIntento número 3
"Enviar no un evento a la vez, sino una lista de eventos es otra idea maravillosa", pensó el equipo. Después de un breve refinamiento de la clase, el equipo implementó el envío de eventos por la lista y recibió valores estables del indicador al nivel de 55-60 cuadros por segundo (Figura 3).
Figura 3. Grabación de pantalla después del tercer intentoConclusiones
La tarea trivial de recopilar análisis se convirtió en un proceso interesante e informativo, durante el cual el equipo bombeó sus habilidades para investigar problemas de rendimiento de aplicaciones y encontrar formas de resolverlos. Espero que nuestra experiencia sea útil tanto para principiantes como para desarrolladores experimentados.
¿Se podría hacer algo más?
Nuestro equipo se decidió por la tercera opción, pero esto no es lo único que podría aplicarse.
En la implementación actual, cuando se
activa el método
onViewAttachedToWindow , las
noticias se transforman en un objeto de evento analítico y, en consecuencia, se crea un nuevo objeto. Una de las posibles soluciones es posponer la conversión hasta el momento del envío: para acumular en la cola no los eventos, sino los elementos de la lista en sí. Entonces la conversión ocurrirá cuando el desplazamiento esté en modo
SCROLL_STATE_IDLE . También puede crear un grupo de objetos para eventos. Juntas, estas acciones pueden proporcionar un aumento adicional en el rendimiento de la aplicación.