Android

22 jun, 2018

Requisitando a localização do usuário da forma correta no Android

Publicidade

Por muitos anos, geolocation foi uma dor de cabeça para desenvolvedores Android. Me lembro claramente nos velhos tempos, onde o stackoverflow e os blogs tinham linhas e mais linhas de instruções sobre como obter a localização do usuário ou updates de localização; todos intitulados “The best way to get user location”. Não acredita? Então dê uma olhada nessa pergunta e tente explicar o que cada instrução faz. Boa sorte!

Mas felizmente toda essa dor de cabeça desapareceu quando a Google introduziu APIs de localização com o Play Services e essas se tornaram padrões, que são utilizados até os dias de hoje. Claro que muita coisa mudou desde então. Algumas coisas foram depreciadas e permissões em runtime foram inseridas na versão M do Android, mas com poucas linhas de código podemos fazer coisas que antes eram monstruosas de codar, e as pessoas, em sua maioria, as utilizam corretamente. Entretanto, algo que eu vejo muito sendo feito errado por aí é requisitar ao usuário o compartilhamento da sua localização.

A imagem acima mostra um usuário que foi redirecionado para a tela de configurações do GPS. Utilizando esse método, o usuário precisa ser redirecionado para outra tela, clicar no toogle para ativar o GPS e voltar para o seu aplicativo. Não é a melhor experiência de usuário possível.

Esse artigo tem o intuito de mostrar como verificar se seu usuário está com o GPS ligado e, caso não esteja, apresentar uma Dialog de Configuração de Localização padrão onde ele poderá atualizar essa configuração com apenas um click.

Antes de mais nada, devemos lembrar que, para chegar nesse ponto, precisamos de alguns pré-requisitos:

Manifest

Aplicativos que usam localização devem ter essas permissões explícitas no manifest. Para este exemplo, usaremos uma localização mais precisa. Para isso, basta incluir a seguinte linha no manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="br.com.sibela.changing_location_settings">


        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


</manifest>

Observação: Se o dispositivo estiver rodando com a versão 6.0 do Android ou superior, e seu app tiver como target SDK a versão 23 ou superior, seu app precisa também requisitar a permissão de localização em runtime. Caso ainda não conheça nada sobre isso, lhe aconselho a ler este artigo, que explica tudo o que você precisa saber sobre.

Criando uma location request

Para armazenar parâmetros e requisitar a localização do usuário, é necessário ter um objeto do tipo LocationRequest. Para este artigo, usaremos o método abaixo, onde esse objeto é um atributo da nossa classe chamado mLocationRequest.

private void createLocationRequest() {
           mLocationRequest = new LocationRequest();
           mLocationRequest.setInterval(10000);
           mLocationRequest.setFastestInterval(5000)
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

}

Obtendo a localização

Uma vez conectado com a API de localização, é possível pegar a localização atual do dispositivo. Para isso, é necessário criar um LocationSettingsRequest e adicionar nossas location requests.

LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);

Em seguida, podemos checar se as configurações de localização estão ligadas:

SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());

Podemos incluir callbacks na tarefa que verifica se a tarefa de verificar as configurações de localização foi concluída com sucesso (o usuário já estava disponibilizando sua localização) ou não.

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
        // Todas as configurações estão ok. Podemos iniciliazar requests de localização aqui :)
     }
});

task.addOnFailureListener(this, new OnFailureListener() {
     @Override
     public void onFailure(@NonNull Exception e) {
        // As configurações não estão ok. Precisamos pedir para o usuário alterá-las
     }
});

Caso o método de falha seja chamado, podemos checar se a exceção é instância da classe ResolvableApiException, que indica que as configurações precisam ser alteradas para então exibir a dialog que pede para o usuário alterá-las chamando o método startResolutionForResult().

if (e instanceof ResolvableApiException) {
     try {
          ResolvableApiException resolvable = (ResolvableApiException) e;
          resolvable.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
     } catch (IntentSender.SendIntentException sendEx) { }
}

Caso algumas coisas acima não façam muito sentido, é preciso entender que:

  • O método startResolutionForResult() é quem pede para exibir a dialog para o usuário;
  • O resultado da escolha do usuário é enviado via callback para a activity, através do onActivityResult();
  • O método startResolutionForResult() recebe dois parâmetros, sendo um deles a activity, pelo qual o callback será chamado, e o outro um int, que será usado para verificarmos por qual motivo esse callback foi chamado;
  • O try catch é obrigatório, mas nesse contexto não teremos nada para verificar no catch.

Feito isso, precisamos apenas sobrescrever o onActivityResult() para verificarmos o que o usuário escolheu, da seguinte forma:

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_CHECK_SETTINGS) {
          switch (resultCode) {

               case Activity.RESULT_OK:
                    // O usuário aceitou compartilhar sua localização :D
                    break;

               case Activity.RESULT_CANCELED:
                    // O usuário não aceitou compartilhar sua localização :’(
                    break
          }
     }
}

Pronto, agora você tem uma forma mais simples e fácil de solicitar a localização do seu usuário, sem muito boilerplate (ok, talvez um pouquinho, mas já está muito bom).

Para a implementação ficar ainda mais fácil, tem um exemplo igual ao que foi mostrado aqui no meu GitHub, então, qualquer dúvida, não deixe de clonar o repositório e deixar um comentário falando o que você achou.