Como coletar análises e não matar a produtividade

O Analytics é parte integrante de um aplicativo móvel moderno. O Analytics permite coletar informações sobre o usuário para desenvolver e melhorar o produto.

Geralmente, a coleta de informações reduz o desempenho do aplicativo. O processo carrega adicionalmente a CPU e a memória, e esse é um preço alto. A operação lenta do aplicativo pode causar críticas negativas aos usuários, diminuir a classificação e levar à perda de audiência.

Nossa equipe de desenvolvedores do Android enfrentou esse problema enquanto trabalhava no próximo projeto, relacionado às notícias. Tivemos que registrar a exibição de cada notícia na lista.

Tentativa número 1


Depois de receber a tarefa de coletar análises, a equipe rapidamente mostrou o resultado. O gatilho para gerar um evento foi o método onViewAttachedToWindow . Tudo parece estar bem, mas com uma rolagem rápida, a interface ficou visivelmente interrompida - algo deu errado. O problema tinha que ser resolvido.

Todo mundo percebe a suspensão de maneira diferente, por isso precisávamos de fatos e evidências. Para medir o atraso, foi escolhido o FPS (quadros por segundo) e o TinyDenser, medidor de FPS, para medir o atraso . Depois de conectar o utilitário, a equipe recebeu uma confirmação objetiva do problema - o indicador caiu, algumas vezes de maneira notável: menos de 30 quadros por segundo, a gravação de tela com o utilitário ligado é mostrada na Figura 1.

imagem
Figura 1. Gravação de tela antes da otimização

Tentativa número 2


E se você adiar o envio de eventos até que o usuário role a lista? Hmmm, a equipe pensou, e decidiu criar uma fila de eventos e enviá-los após o fim do pergaminho. Tudo é simples aqui: adicionamos OnScrollListener ao RecyclerView e aguardamos até que o newState esteja vazio SCROLL_STATE_IDLE - o problema está parcialmente resolvido.

class IdleStateScrollListener(private val analyticsFacade: AnalyticsFacade) : RecyclerView.OnScrollListener() { fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { analyticsFacade.setPending(newState != RecyclerView.SCROLL_STATE_IDLE) } } 

O próximo passo é implementar o acúmulo de eventos e seu envio.

Para gerenciar a fila, criamos uma classe responsável por adicionar eventos à fila e enviar análises ao serviço. Para envio periódico, escolhemos um ScheduledExecutorService com um encadeamento que executava Runnable a cada segundo, a hora foi selecionada empiricamente.

Isso imediatamente produziu resultados, um aumento significativo no FPS. Em princípio, o problema foi resolvido; na Figura 2, vemos o resultado da aplicação após a segunda tentativa. Mas havia apenas uma tarefa: os eventos foram enviados para o serviço, o que levou à geração frequente de objetos da classe Intent , além de sobrecarregar o GC e fornecer "amenidades" na forma de pausas do tipo " pare o mundo" .

imagem
Figura 2. Gravação de tela após a segunda tentativa

Tentativa número 3


“Enviar não um evento de cada vez, mas uma lista de eventos é outra ideia maravilhosa”, pensou a equipe. Após um breve refinamento da classe, a equipe implementou o envio de eventos pela lista e recebeu valores estáveis ​​de indicadores no nível de 55 a 60 quadros por segundo (Figura 3).

imagem

Figura 3. Gravação de tela após a terceira tentativa

Conclusões


A tarefa trivial de coletar análises se transformou em um processo interessante e informativo, durante o qual a equipe investiu suas habilidades em pesquisar problemas de desempenho de aplicativos e encontrar maneiras de resolvê-los. Espero que nossa experiência seja útil para desenvolvedores iniciantes e experientes.

Poderia algo mais ser feito?


Nossa equipe optou pela terceira opção, mas essa não é a única coisa que pode ser aplicada.

Na implementação atual, quando o método onViewAttachedToWindow é acionado, as notícias são transformadas em um objeto de evento de análise e, portanto, um novo objeto é criado. Uma das soluções possíveis é adiar a conversão até o momento do envio: acumular na fila não os eventos, mas os próprios elementos da lista. A conversão ocorrerá quando o rolo estiver no modo SCROLL_STATE_IDLE . Você também pode criar um pool de objetos para eventos. Juntas, essas ações podem proporcionar um aumento adicional no desempenho do aplicativo.

Source: https://habr.com/ru/post/pt414899/


All Articles