O uso do rádio sem fio para transferir dados é, possivelmente, uma das fontes mais significativas de consumo de bateria do seu app. Para minimizar o consumo de bateria associado à atividade de rede, é essencial entender como seu modelo de conectividade afetará o hardware de rádio subjacente.
Esta seção apresenta a máquina de estado de rádio sem fio e explica como o modelo de conectividade do seu app interage com ela. Em seguida, ele oferece várias técnicas que, quando seguidas, ajudam a minimizar o efeito do consumo de dados do app na bateria.
A máquina de estado de rádio
O rádio sem fio no dispositivo do usuário tem recursos de economia de energia integrados que ajudam a minimizar o consumo de bateria. Quando totalmente ativo, o rádio sem fio consome uma quantidade significativa de energia, mas, quando inativo ou em espera, ele consome muito pouca energia.
Um fator importante a ser lembrado é que o rádio não pode se mover do modo de espera para totalmente ativo instantaneamente. Há um período de latência associado ao "ligamento" do rádio. Dessa forma, a bateria transita de estados de energia mais altos para os mais baixos de forma lenta, a fim de economizar energia quando não está em uso e, ao mesmo tempo, tentar minimizar a latência associada ao "carregamento" do rádio.
A máquina de estado para um rádio de rede 3G geralmente consiste em três estados de energia:
- Potência total: usada quando uma conexão está ativa, permitindo que o dispositivo transfira dados na taxa mais alta possível.
- Baixa potência: um estado intermediário que reduz o consumo de energia da bateria em cerca de 50%.
- Em espera: o estado de consumo mínimo de energia em que nenhuma conexão de rede fica ativa.
Embora os estados de baixa potência e em espera consumam muito menos bateria, eles também introduzem uma latência considerável nas solicitações de rede. Retornar à potência total do estado baixo leva cerca de 1,5 segundo, e a mudança do modo de espera para a potência total pode levar mais de 2 segundos.
Para minimizar a latência, a máquina de estado usa um atraso para adiar a transição para estados de energia mais baixos. A Figura 1 usa os horários da AT&T para um rádio 3G típico.
A máquina de estado de rádio em cada dispositivo, principalmente o atraso de transição associado ("tempo de cauda") e a latência de inicialização, varia de acordo com a tecnologia de rádio sem fio empregada (3G, LTE, 5G e assim por diante) e é definida e configurada pela rede da operadora em que o dispositivo está operando.
Nesta página, descrevemos uma máquina de estado representativa para um rádio sem fio 3G típico, com base nos dados fornecidos pela AT&T. No entanto, os princípios gerais e as práticas recomendadas resultantes são aplicáveis a todas as implementações de rádio sem fio.
Essa abordagem é particularmente eficaz para a navegação na Web para dispositivos móveis típica, porque evita a latência indesejada enquanto os usuários navegam. O tempo de cauda relativamente baixo também garante que, quando uma sessão de navegação terminar, o rádio possa mover para um estado de energia mais baixo.
Infelizmente, essa abordagem pode levar a apps ineficientes em sistemas operacionais de smartphones modernos, como o Android, em que os apps são executados em primeiro plano (quando a latência é importante) e em segundo plano (em que a duração da bateria precisa ser priorizada).
Como os apps afetam a máquina de estado de rádio
Cada vez que você cria uma nova conexão de rede, o rádio transita para o estado de potência total. No caso da máquina de estado de rádio 3G típica descrita anteriormente, ela permanecerá em potência total durante a transferência, mais 5 segundos adicionais de tempo de cauda, seguidos por 12 segundos no estado de baixa energia. Portanto, para um dispositivo 3G típico, toda sessão de transferência de dados fará com que o rádio consuma energia por pelo menos 18 segundos.
Na prática, isso significa que um app que faz uma transferência de dados de um segundo, três vezes por minuto, manterá o rádio sem fio perpetuamente ativo, movendo-o de volta para a alta potência assim que ele entrar no modo de espera.
Por comparação, se o mesmo app agrupasse as transferências de dados, executando uma única transferência de três segundos a cada minuto, isso manteria o rádio no estado de alta potência por apenas 20 segundos por minuto no total. Isso permitiria que o rádio ficasse em espera por 40 segundos a cada minuto, resultando em uma redução significativa no consumo de bateria.
Técnicas de otimização
Agora que você entende como o acesso à rede afeta a duração da bateria, vamos falar sobre o que você pode fazer para reduzir o consumo da bateria e, ao mesmo tempo, fornecer uma experiência do usuário rápida e fluida.
Transferências de dados do pacote
Como mencionado na seção anterior, agrupar suas transferências de dados para transferi-los com menos frequência é uma das melhores maneiras de melhorar a eficiência da bateria.
É claro que isso nem sempre é possível se o app precisa receber ou enviar dados imediatamente em resposta a uma ação do usuário. É possível atenuar isso antecipando e pré-buscando dados. Outros cenários, como o envio de registros ou análises para um servidor e outras transferências de dados não urgentes e iniciadas pelo app, funcionam muito bem com lotes e agrupamento. Consulte Como otimizar tarefas iniciadas pelo app para dicas sobre como programar transferências de rede em segundo plano.
Fazer pré-busca de dados
A pré-busca de dados é outra maneira eficaz de reduzir o número de sessões independentes de transferência de dados executadas pelo app. Com a pré-busca, quando o usuário realiza uma ação, o app prevê quais dados provavelmente serão necessários para a próxima série de ações do usuário e os busca em um único burst, em uma única conexão, com capacidade total.
Ao carregar suas transferências, você reduz o número de ativações de rádio necessárias para fazer o download de dados. Como resultado, você não apenas conserva a duração da bateria, mas também melhora a latência, reduz a largura de banda necessária e reduz os tempos de download.
A pré-busca também oferece uma experiência do usuário aprimorada, minimizando a latência no app causada pela espera da conclusão dos downloads antes de executar uma ação ou visualizar dados.
Aqui está um exemplo prático.
Um leitor de notícias
Muitos apps de notícias tentam reduzir a largura de banda fazendo o download de manchetes só depois de uma categoria ser selecionada, de artigos completos apenas quando o usuário quer lê-los e de miniaturas assim que elas são exibidas na tela.
Usando essa abordagem, o rádio é forçado a permanecer ativo para a maioria das sessões de leitura de notícias dos usuários enquanto eles rolam as manchetes, mudam de categoria e leem artigos. Além disso, a troca constante entre estados de energia resulta em latência significativa ao trocar de categoria ou ler artigos.
Uma abordagem melhor é fazer a pré-busca de uma quantidade razoável de dados na inicialização, começando pelo primeiro conjunto de manchetes e miniaturas (o que garante um tempo de inicialização de baixa latência) e continuando com as manchetes e miniaturas restantes, bem como o texto de cada artigo disponível pelo menos da lista de manchetes principais.
Outra alternativa é fazer a pré-busca de todas as manchetes, miniaturas, textos de artigos e possivelmente até fotos de artigos completos, normalmente em segundo plano em um horário predeterminado. Como essa abordagem corre o risco de consumir uma quantidade significativa de largura de banda e duração da bateria para fazer o download de conteúdo que nunca será usado, implemente-a com cuidado.
Outras considerações
Embora a pré-busca de dados tenha muitos benefícios, uma pré-busca muito agressiva também apresenta o risco de aumentar o consumo de bateria e o uso de largura de banda, bem como a cota de download, ao fazer o download de dados que não são usados. Também é importante garantir que a pré-busca não atrase a inicialização do app enquanto o app aguarda o término da pré-busca. Em termos práticos, isso pode significar processar dados progressivamente ou iniciar transferências consecutivas priorizadas, de modo que os dados necessários para a inicialização do aplicativo sejam transferidos por download e processados primeiro.
A agressividade para fazer a pré-busca de dados depende do tamanho dos dados que estão sendo transferidos por download e da probabilidade de serem usados. Como orientação geral, com base na máquina de estado descrita anteriormente, para dados que têm 50% de chance de serem usados na sessão atual do usuário, normalmente é possível fazer a pré-busca por cerca de 6 segundos (aproximadamente 1 a 2 megabytes) antes que o custo potencial de fazer o download de dados não utilizados corresponda à possível economia de não fazer o download desses dados.
De modo geral, uma prática recomendada é pré-buscar dados de maneira que você só precise iniciar outro download a cada 2 a 5 minutos e na ordem de 1 a 5 megabytes.
Seguindo esse princípio, downloads grandes, como arquivos de vídeo, precisam ser transferidos em blocos em intervalos regulares (a cada 2 a 5 minutos), realizando a pré-busca apenas dos dados de vídeo que provavelmente serão visualizados nos próximos minutos.
Uma solução é programar que o download completo ocorra apenas quando o dispositivo estiver conectado ao Wi-Fi e, possivelmente, apenas quando estiver carregando. A API WorkManager é compatível exatamente com esse caso de uso, permitindo que você restrinja o trabalho em segundo plano até que o dispositivo atenda aos critérios especificados pelo desenvolvedor, como carregar e conectar-se ao Wi-Fi.
Verificar a conectividade antes de fazer solicitações
A pesquisa por um sinal de celular é uma das operações que mais consomem energia em um
dispositivo móvel. Uma prática recomendada para solicitações iniciadas pelo usuário é primeiro verificar se há
uma conexão usando
ConnectivityManager
, conforme mostrado em
Monitorar o status da conectividade e a medição
da conexão.
Se não houver rede, o app poderá economizar bateria sem forçar o rádio móvel
a pesquisar. Assim, a solicitação pode ser programada e executada em um lote com outras solicitações quando uma conexão é feita.
Conexões de pool
Outra estratégia que pode ajudar além do lote e da pré-busca é agrupar as conexões de rede do app.
Geralmente, é mais eficiente reutilizar as conexões de rede atuais do que iniciar novas. A reutilização de conexões também permite que a rede reaja de maneira mais inteligente ao congestionamento e a problemas de dados de rede relacionados.
O HttpURLConnection
e a maioria dos clientes HTTP, como OkHttp, ativam o pool de conexões por padrão e reutilizam a mesma conexão para várias solicitações.
Recapitulação e perspectiva do futuro
Nesta seção, você aprendeu muito sobre o rádio sem fio e algumas estratégias que podem ser aplicadas amplamente para proporcionar uma experiência do usuário rápida e responsiva, além de reduzir o consumo de bateria.
Na próxima seção, analisaremos em detalhes três tipos distintos de interações de rede, que são comuns na maioria dos apps. Você vai aprender os motivadores para cada um desses tipos, além de técnicas e APIs modernas para gerenciar essas interações de forma eficiente.