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.LocationListenere 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 LocationManagersistema, implementa LocationListenere chama requestLocationUpdateso 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.ConnectionCallbackse fazer GooglePlayServicesClient.OnConnectionFailedListenerinterface. 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 locationser 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.LocationListenerinterface 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 onConnectedretorno de chamada, ou você receberá um IllegalStateExceptionporque 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 onCreatemé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 locationEnabledbandeira no seu onConnectedmé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.