Localização do usuário no Android
Obter a localização do usuário no Android é um pouco menos direto do que no iOS. Para começar a confusão, existem duas maneiras totalmente diferentes de fazer isso. O primeiro está usando APIs do Android android.location.LocationListener
e o segundo está usando as APIs do Google Play Services com.google.android.gms.location.LocationListener
. Vamos passar por ambos.
API de localização do Android
As APIs de localização do Android usam três provedores diferentes para obter a localização -
LocationManager.GPS_PROVIDER
- Este provedor determina a localização usando satélites. Dependendo das condições, esse provedor pode demorar um pouco para retornar uma correção de local.
LocationManager.NETWORK_PROVIDER
- Este provedor determina a localização com base na disponibilidade da torre de celular e pontos de acesso Wi-Fi. Os resultados são recuperados por meio de uma pesquisa de rede.
LocationManager.PASSIVE_PROVIDER
- Este provedor retornará locais gerados por outros fornecedores. Você recebe atualizações de localização passivamente quando outros aplicativos ou serviços as solicitam sem realmente solicitar os locais.
A essência disso é que você obtém um objeto do LocationManager
sistema, implementa LocationListener
e chama requestLocationUpdates
o LocationManager
.
Aqui está um trecho de código:
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
Guia da API do Google sobre estratégias de localizaçãoexplica o código muito bem. Mas eles também mencionam que, na maioria dos casos, você obtém melhor desempenho da bateria e precisão mais apropriada usando a API dos Serviços de Localização do Google . Agora a confusão começa!
- API de serviços de localização do Google
A API dos Serviços de Localização do Google faz parte do APK do Google Play Services (veja como configurá-lo ). Eles são construídos sobre a API do Android. Essas APIs fornecem um "provedor de localização fundida" em vez dos provedores mencionados acima. Esse provedor escolhe automaticamente o provedor subjacente a ser usado, com base na precisão, no uso da bateria etc. É rápido porque você obtém a localização de um serviço em todo o sistema que o atualiza constantemente. E você pode usar recursos mais avançados, como geofencing.
Para usar os Serviços de Localização do Google, seu aplicativo precisa se conectar ao GooglePlayServicesClient
. Para se conectar ao cliente, sua atividade (ou fragmento, mais ou menos) precisa implementar GooglePlayServicesClient.ConnectionCallbacks
e fazer GooglePlayServicesClient.OnConnectionFailedListener
interface. Aqui está um código de exemplo:
public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {
LocationClient locationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
locationClient = new LocationClient(this, this, this);
}
@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation() ;
Toast.makeText(this, "Connected to Google Play Services", Toast.LENGTH_SHORT).show();
}
@Override
public void onDisconnected() {
Toast.makeText(this, "Connected from Google Play Services.", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// code to handle failed connection
// this code can be found here — http://developer.android.com/training/location/retrieve-current.html
}
- Por que é
locationClient.getLastLocation()
nulo?
O locationClient.getLastLocation()
obtém o último local conhecido do cliente. No entanto, o provedor de localização fundida somente manterá a localização em segundo plano se pelo menos um cliente estiver conectado a ela. Depois que o primeiro cliente se conectar, ele tentará imediatamente obter um local. Se sua atividade for o primeiro cliente a se conectar e você ligar getLastLocation()
imediatamente onConnected()
, isso poderá não ser suficiente para o primeiro local entrar. Isso resultará em location
ser null
.
Para resolver esse problema, é necessário aguardar (indeterminadamente) até que o provedor obtenha o local e depois ligar getLastLocation()
, o que é impossível saber. Outra opção (melhor) é implementar a com.google.android.gms.location.LocationListener
interface para receber atualizações periódicas de localização (e desativá-la assim que você receber a primeira atualização).
public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
// . . . . . . . . more stuff here
LocationRequest locationRequest;
LocationClient locationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// . . . . other initialization code
locationClient = new LocationClient(this, this, this);
locationRequest = new LocationRequest();
// Use high accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
locationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
locationRequest.setFastestInterval(FASTEST_INTERVAL);
}
// . . . . . . . . other methods
@Override
public void onConnected(Bundle bundle) {
Location location = locationClient.getLastLocation();
if (location == null)
locationClient.requestLocationUpdates(locationRequest, this);
else
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
// . . . . . . . . other methods
@Override
public void onLocationChanged(Location location) {
locationClient.removeLocationUpdates(this);
// Use the location here!!!
}
Nesse código, você está verificando se o cliente já tem o último local (em onConnected
). Caso contrário, você está solicitando atualizações de local e desativando as solicitações (no onLocationChanged()
retorno de chamada) assim que receber uma atualização.
Observe que ele locationClient.requestLocationUpdates(locationRequest, this);
precisa estar dentro do onConnected
retorno de chamada, ou você receberá um IllegalStateException
porque estará tentando solicitar locais sem estar conectado ao cliente do Google Play Services.
- O usuário desativou os Serviços de Localização
Muitas vezes, o usuário teria os serviços de localização desativados (para economizar bateria ou motivos de privacidade). Nesse caso, o código acima ainda solicitará atualizações de local, masonLocationChanged
nunca será chamado. Você pode interromper as solicitações verificando se o usuário desativou os serviços de localização.
Se o seu aplicativo exigir que eles ativem os serviços de localização, você deseja mostrar uma mensagem ou um brinde. Infelizmente, não há como verificar se o usuário desativou os serviços de localização na API de serviços de localização do Google. Para isso, você precisará recorrer à API do Android.
No seu onCreate
método:
LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationEnabled = false;
Toast.makeText(getActivity(), "Enable location services for accurate data", Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;
E use a locationEnabled
bandeira no seu onConnected
método assim:
if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}
ATUALIZAR
O documento é atualizado, o LocationClient é removido e a API suporta o GPS com um clique na caixa de diálogo:
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});
task.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
Link https://developer.android.com/training/location/change-location-settings#prompt
Novo cliente de localização: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
É recomendável acessar https://developer.android.com/training/location antes de executar qualquer tarefa de localização.