Otimizar localização para poupar bateria

Os Limites da localização em segundo plano apresentados no Android 8.0 (API de nível 26) trouxeram um novo foco com relação a como o uso dos serviços de localização afetam o consumo de bateria. Esta página aborda algumas práticas recomendadas dos serviços de localização e o que pode ser feito agora para que o aproveitamento de bateria dos seus aplicativos seja mais eficiente. Adotar essas práticas traz vantagens ao seu aplicativo, independentemente da versão da plataforma em que ele opera.

Os limites da localização em segundo plano no Android 8.0 apresentaram as mudanças a seguir:

  • A coleta de localização em segundo plano é limitada e a localização é calculada e entregue apenas algumas vezes por hora.
  • As verificações de Wi-Fi são mais conservadoras e as atualizações de localização não são computadas quando o dispositivo permanece conectado ao mesmo ponto de acesso estático.
  • A responsividade da fronteira geográfica virtual muda de dezenas de segundos para aproximadamente dois minutos. Essa alteração melhora notavelmente o desempenho da bateria: até 10 vezes mais eficiência em alguns dispositivos.

Esta página parte do princípio de que você esteja usando as APIs dos serviços de localização do Google, que oferecem maior precisão e impõem um gasto de bateria menor do que as APIs de localização da biblioteca. Em particular, esta página supõe familiaridade com a API do provedor de localização misto, que combina sinais de GPS, Wi-Fi e redes de celular, além do acelerômetro, giroscópio, magnetômetro e outros sensores. Também é necessário conhecer a API da fronteira geográfica virtual, criada com base na API do provedor de localização misto e otimizada para o desempenho de bateria.

Entender o consumo de bateria

A coleta de localização e o consumo de bateria têm relação direta nos aspectos a seguir:

  • Precisão: a exatidão dos dados de localização. Em geral, quanto melhor a precisão, maior será o consumo de bateria.
  • Frequência: com que regularidade a localização é calculada. Quanto maior a frequência do cálculo, mais a bateria será usada.
  • Latência: a velocidade de entrega dos dados de localização. Uma latência menor geralmente requer menos consumo de bateria.

Precisão

É possível especificar a precisão da localização com o método setPriority(), passando um dos valores a seguir como argumento:

  • PRIORITY_HIGH_ACCURACY fornece a localização mais precisa possível, calculada com quantas entradas forem necessárias (há a ativação de GPS, Wi-Fi e celular, além do uso de diversos Sensores) e pode causar um consumo significativo de bateria.
  • PRIORITY_BALANCED_POWER_ACCURACY fornece localização precisa com otimização de energia. É muito raro o uso do GPS nesse caso. Normalmente é usada uma combinação de informações de Wi-Fi e celular para calcular a localização do dispositivo.
  • PRIORITY_LOW_POWER depende fortemente das torres de celular e evita as entradas de GPS e Wi-Fi, fornecendo uma precisão aproximada (no nível da cidade) com o mínimo consumo possível de bateria.
  • PRIORITY_NO_POWER recebe as localizações passivamente de outros aplicativos para os quais a localização já foi calculada.

As necessidades de localização da maioria dos aplicativos podem ser atendidas por meio de opções de energia baixa ou equilibrada. A alta precisão deve ser reservada para aplicativos que operam em primeiro plano e exigem atualizações de localização em tempo real (por exemplo, um aplicativo de mapa).

Frequência

Há dois métodos possíveis para especificar a frequência da localização:

  • Use o método setinterval() para especificar o intervalo em que a localização é calculada para seu aplicativo.
  • Use o setFastestInterval() para especificar o intervalo em que a localização calculada para outros aplicativos é entregue ao seu aplicativo.

Ao usar setInterval(), passe o maior valor possível. Isso é especialmente verdade com relação à coleta de localização em segundo plano, que costuma ser uma fonte de consumo indesejado de bateria. Usar intervalos de alguns segundos é algo a ser reservado para os casos de uso em primeiro plano. Os limites de localização em segundo plano introduzidos no Android 8.0 impõem essas estratégias, mas seu aplicativo precisa se esforçar para aplicá-las nos dispositivos Android 7.0 ou versões anteriores.

Latência

É possível especificar a latência com o método setMaxWaitTime(), normalmente passando um valor muitas vezes maior do que o intervalo especificado no método setInterval(). Essa configuração atrasa a entrega da localização e muitas atualizações de locais podem ser entregues em lotes. As duas alterações citadas ajudam a minimizar o consumo de bateria.

Caso o aplicativo não precise da atualização de local imediatamente, passe o maior valor possível ao método setMaxWaitTime(), efetivamente trocando a latência por mais dados e eficiência de bateria.

Ao usar fronteiras geográficas virtuais, os aplicativos precisam passar um valor alto no método setNotificationResponsiveness() para economizar energia. É recomendado um valor de cinco minutos ou mais.

Casos de uso da localização

Esta seção descreve alguns cenários de coleta de localização típicos e recomendações para otimizar o uso das APIs do provedor de localização misto e da fronteira geográfica virtual.

Atualizações visíveis ao usuário ou em primeiro plano

Exemplo: um aplicativo de mapa que precisa de atualizações frequentes e precisas com latência muito baixa. Todas as atualizações acontecem em primeiro plano: o usuário inicia uma atividade, consome os dados de localização e, após algum tempo, interrompe a atividade.

Use o método setPriority() com um valor de PRIORITY_HIGH_ACCURACY ou PRIORITY_BALANCED_POWER_ACCURACY.

O intervalo especificado no método setInterval() depende do caso de uso: para cenários em tempo real, defina o valor de alguns segundos. Caso contrário, limite a alguns minutos (aproximadamente dois minutos ou mais é o recomendado para minimizar o uso da bateria).

Como descobrir a localização do dispositivo

Exemplo: um aplicativo de meteorologia quer descobrir a localização do dispositivo.

Use o método getLastLocation(), que retorna o local disponível mais recentemente (que em casos raros pode ser nulo). Esse método fornece uma maneira simples de acessar a localização sem incorrer em custos associados às solicitações de atualizações de local. Use em conjunto com o método isLocationAvailable(), que retorna true quando a localização retornada por getLastLocation() está razoavelmente atualizada.

Como iniciar atualizações quando um usuário está em uma localização específica

Exemplo: solicitar atualizações quando um usuário está a certa distância do trabalho, de casa ou de outro local.

Use a fronteira geográfica virtual em conjunto com as atualizações do provedor de localização misto. Solicite as atualizações quando o aplicativo receber um acionador de entrada da fronteira geográfica virtual e as remova quando o aplicativo receber um acionador de saída desse tipo de fronteira. Isso garante que o aplicativo tenha atualizações de localização mais granulares somente quando o usuário tiver inserido uma área definida.

O fluxo de trabalho típico para esse cenário pode envolver o surgimento de uma notificação na transição de entrada da fronteira geográfica virtual e o início de uma atividade que contém código para solicitar atualizações quando o usuário toca na notificação.

Como iniciar atualizações com base no estado da atividade do usuário

Exemplo: solicitar atualizações somente quando o usuário estiver dirigindo ou pedalando.

Use a API de reconhecimento da atividade em conjunto com as atualizações do provedor de localização misto. Solicite as atualizações quando a atividade direcionada for detectada e remova as atualizações quando o usuário parar de executar a atividade.

O fluxo de trabalho típico para esse caso de uso pode envolver o surgimento de uma notificação para a atividade detectada e o início de uma atividade que contém código para solicitar atualizações quando o usuário toca na notificação.

Atualizações de localização em segundo plano de longa duração vinculadas a áreas geográficas

Exemplo: o usuário quer ser notificado quando o dispositivo estiver próximo a um revendedor.

Esse é um excelente caso de uso para a fronteira geográfica virtual. Como esse caso certamente envolve localização em segundo plano, use o método addGeofences(GeofencingRequest, PendingIntent).

Defina as opções de configuração a seguir:

  • Se estiver acompanhando transições de pausa, use o método setLoiteringDelay() passando um valor de cinco minutos ou menos.

  • Use a setNotificationResponsiveness(), passando um valor de aproximadamente cinco minutos. No entanto, considere usar um valor de cerca de 10 minutos se o aplicativo puder gerenciar o atraso extra na responsividade.

Um aplicativo só pode registrar no máximo 100 fronteiras geográficas virtuais. Em um caso de uso em que um aplicativo quer acompanhar uma grande quantidade de opções de revendedores, pode ser necessário que ele registre uma ampla fronteira geográfica virtual (no nível da cidade). Além disso, ele precisará registrar dinamicamente fronteiras menores (para locais na cidade) para lojas dentro da fronteira maior. Quando o usuário insere uma fronteira geográfica virtual maior, fronteiras menores podem ser adicionadas. Uma vez que o usuário saia da fronteira maior, as menores podem ser removidas e as fronteiras em geral podem ser registradas novamente em uma nova área.

Atualizações de localização em segundo plano de longa duração sem um componente do aplicativo visível

Exemplo: um aplicativo que acompanha a localização de forma passiva

Se possível, use o método setPriority() com a opção PRIORITY_NO_POWER. Isso incorre em praticamente nenhum consumo de bateria. Caso o uso de PRIORITY_NO_POWER não seja possível, use PRIORITY_BALANCED_POWER_ACCURACY ou PRIORITY_LOW_POWER, mas evite PRIORITY_HIGH_ACCURACY para trabalho sustentado em segundo plano, uma vez que essa opção consome substancialmente a bateria.

Se precisar de mais dados de localização, use a localização passiva. Para isso, chame o método setFastestInterval() passando um valor menor do que o passado para setInterval(). A localização passiva, combinada com a opção PRIORITY_NO_POWER, pode entregar de maneira oportuna a localização calculada por outros aplicativos sem custo extra.

Modere a frequência adicionando alguma latência. Para isso, use o método setMaxWaitTime(). Por exemplo, se você usar o método setinterval() com um valor em torno de 10 minutos, considere chamar setMaxWaitTime() com um valor entre 30 a 60 minutos. Ao usar essas opções, a localização é calculada para seu aplicativo a aproximadamente cada 10 minutos, mas o aplicativo só é ativado a cada 30 a 60 minutos com alguns dados de localização disponíveis como uma atualização em lote. Essa abordagem troca a latência por mais dados disponíveis e melhoria no desempenho da bateria.

Atualizações frequentes de alta precisão enquanto o usuário interage com outros aplicativos

Exemplo: um aplicativo de navegação ou fitness que continua a funcionar quando o usuário desliga a tela ou abre um aplicativo diferente.

Use um serviço em primeiro plano. Se houver a possibilidade de um trabalho pesado ser feito pelo seu aplicativo em nome do usuário, é uma prática recomendada informá-lo sobre esse trabalho. Um serviço em primeiro plano requer uma notificação persistente. Para saber mais, consulte Visão geral das notificações.

Práticas recomendadas de localização

A implementação das práticas recomendadas nesta seção ajuda a reduzir o uso que seu aplicativo faz da bateria.

Remover atualizações de local

Uma fonte comum de consumo desnecessário de bateria é a não remoção das atualizações de local quando você não precisa mais delas. Isso pode acontecer, por exemplo, quando os métodos do ciclo de vida onStart() ou onResume() da atividade contêm uma chamada para requestlocationUpdates() sem uma chamada correspondente para removeLocationUpdates() nos métodos do ciclo de vida onPause() ou onStop().

Você pode usar componentes cientes do ciclo de vida para gerenciar melhor os ciclos das atividades no seu aplicativo. Para saber mais, consulte Como gerenciar componentes cientes do ciclo de vida.

Definir limites de tempo

Para evitar consumo de bateria, defina um tempo limite razoável para a interrupção das atualizações de local. Esse limite garante que as atualizações não continuem de forma indefinida, além de proteger o aplicativo em cenários onde as atualizações são solicitadas, mas não removidas (por exemplo, devido a um bug no código).

Para uma solicitação do provedor de localização misto, adicione um tempo limite chamando setExpirationDuration(), que recebe um parâmetro responsável por apresentar o tempo em milissegundos desde a última vez em que o método foi chamado. Também é possível adicionar um tempo limite chamando setExpirationTime(), que recebe um parâmetro responsável por representar o tempo de expiração em milissegundos desde a última inicialização do sistema.

Para adicionar um tempo limite a uma solicitação de localização da fronteira geográfica virtual, chame o método setExpirationDuration().

Solicitações de lote

Para todos os casos de uso que não são em primeiro plano, agrupe várias solicitações em lote. Você pode usar o método setInterval() para especificar o intervalo em que o cálculo da localização ocorrerá. Em seguida, use o método setMaxWaitTime() para definir o intervalo em que a localização é entregue ao seu aplicativo. O valor passado ao método setMaxWaitTime() precisa ser um múltiplo do valor passado ao método setInterval(). Por exemplo, considere a solicitação de local a seguir:

Kotlin

val request = LocationRequest()
request.setInterval(10 * 60 * 1000)
request.setMaxWaitTime(60 * 60 * 1000)

Java

LocationRequest request = new LocationRequest();
request.setInterval(10 * 60 * 1000);
request.setMaxWaitTime(60 * 60 * 1000);

Nesse caso, a localização é calculada, em média, a cada 10 minutos e cerca de seis pontos de dados de localização são entregues em um lote, aproximadamente a cada hora. Embora ainda receba atualizações de local a cada 10 minutos, você economiza bateria porque seu dispositivo é ativado apenas a cada hora.

Usar atualizações de local passivas

Nos casos de uso em segundo plano, é recomendável limitar as atualizações de local. Os limites do Android 8.0 impõem essa prática, mas os aplicativos que operam em dispositivos mais antigos precisam se esforçar para limitar ao máximo possível a localização em segundo plano.

É provável que, enquanto seu aplicativo esteja em segundo plano, outro aplicativo possa solicitar frequentemente atualizações de local em primeiro plano. Os serviços de localização disponibilizam essas atualizações para seu aplicativo. Considere a solicitação de localização a seguir, que consome dados de localização de forma oportuna:

Kotlin

val request = LocationRequest()
request.setInterval(15 * 60 * 1000)
request.setFastestInterval(2 * 60 * 1000)

Java

LocationRequest request = new LocationRequest();
request.setInterval(15 * 60 * 1000);
request.setFastestInterval(2 * 60 * 1000);

No exemplo anterior, a localização é calculada para o aplicativo aproximadamente a cada 15 minutos. Caso outros aplicativos solicitem a localização, os dados são disponibilizados para seu aplicativo em um intervalo máximo de dois minutos.

Embora o consumo de localização de forma passiva não incorra em gasto de bateria, tome muito cuidado nos casos em que o recebimento de dados de localização acione operações pesadas de CPU ou I/O. Para minimizar os custos de bateria, o intervalo especificado em setFastestInterval() não pode ser pequeno demais.

Ao seguir as recomendações desta página, você pode melhorar de forma significativa o desempenho de bateria dos dispositivos dos seus usuários. É menos provável que os usuários excluam aplicativos que não consomem a bateria.