Localisation de l'utilisateur sur Android
Obtenir la position de l'utilisateur sur Android est un peu moins simple que sur iOS. Pour commencer la confusion, il existe deux façons totalement différentes de le faire. Le premier utilise les API Android de android.location.LocationListener
, et le second utilise les API des services Google Play com.google.android.gms.location.LocationListener
. Passons en revue les deux.
API de localisation d'Android
Les API de localisation d'Android utilisent trois fournisseurs différents pour obtenir la localisation -
LocationManager.GPS_PROVIDER
- Ce fournisseur détermine l'emplacement à l'aide de satellites. Selon les conditions, ce fournisseur peut prendre un certain temps pour renvoyer un correctif d'emplacement.
LocationManager.NETWORK_PROVIDER
- Ce fournisseur détermine l'emplacement en fonction de la disponibilité de la tour cellulaire et des points d'accès WiFi. Les résultats sont récupérés au moyen d'une recherche réseau.
LocationManager.PASSIVE_PROVIDER
- Ce fournisseur renverra les emplacements générés par d'autres fournisseurs. Vous recevez passivement des mises à jour de localisation lorsque d'autres applications ou services en font la demande sans en faire la demande.
L'essentiel est que vous obtenez un objet du LocationManager
système, implémentez le LocationListener
et appelez le requestLocationUpdates
sur le LocationManager
.
Voici un extrait de code:
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);
Guide API de Google sur les stratégies de localisationexplique assez bien le code. Mais ils mentionnent également que dans la plupart des cas, vous obtiendrez de meilleures performances de la batterie, ainsi qu'une précision plus appropriée, en utilisant plutôt l' API Google Location Services . Maintenant, la confusion commence!
- API des services de localisation de Google
L'API des services de localisation de Google fait partie de l'APK des services Google Play ( voici comment la configurer ). Ils sont construits sur l'API d'Android. Ces API fournissent un «fournisseur d'emplacement fusionné» au lieu des fournisseurs mentionnés ci-dessus. Ce fournisseur choisit automatiquement le fournisseur sous-jacent à utiliser, en fonction de la précision, de l'utilisation de la batterie, etc. Il est rapide car vous obtenez l'emplacement d'un service à l'échelle du système qui continue de le mettre à jour. Et vous pouvez utiliser des fonctionnalités plus avancées telles que le géorepérage.
Pour utiliser les services de localisation de Google, votre application doit se connecter au GooglePlayServicesClient
. Pour vous connecter au client, votre activité (ou fragment, ou presque) doit être implémentée GooglePlayServicesClient.ConnectionCallbacks
et GooglePlayServicesClient.OnConnectionFailedListener
s'interfacer. Voici un exemple de code:
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
}
- Pourquoi est
locationClient.getLastLocation()
nul?
Le locationClient.getLastLocation()
obtient le dernier emplacement connu du client. Cependant, le fournisseur d'emplacement fusionné ne conservera l'emplacement en arrière-plan que si au moins un client y est connecté. Une fois le premier client connecté, il essaiera immédiatement d'obtenir un emplacement. Si votre activité est le premier client de se connecter et que vous appelez getLastLocation()
tout de suite dans onConnected()
, qui pourrait ne pas être assez de temps pour le premier emplacement à venir. Cela se traduira par location
être null
.
Pour résoudre ce problème, vous devez attendre (indéterminé) jusqu'à ce que le fournisseur obtienne l'emplacement, puis appeler getLastLocation()
, ce qui est impossible à savoir. Une autre (meilleure) option consiste à implémenter l' com.google.android.gms.location.LocationListener
interface pour recevoir des mises à jour de localisation périodiques (et à la désactiver une fois que vous avez obtenu la première mise à jour).
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!!!
}
Dans ce code, vous vérifiez si le client possède déjà le dernier emplacement (in onConnected
). Sinon, vous demandez des mises à jour de localisation et désactivez les demandes (en onLocationChanged()
rappel) dès que vous recevez une mise à jour.
Notez que le locationClient.requestLocationUpdates(locationRequest, this);
doit être dans le onConnected
rappel, sinon vous obtiendrez un IllegalStateException
car vous tenterez de demander des emplacements sans être connecté au client des services Google Play.
- L'utilisateur a désactivé les services de localisation
Plusieurs fois, l'utilisateur aurait désactivé les services de localisation (pour économiser la batterie ou pour des raisons de confidentialité). Dans un tel cas, le code ci-dessus demandera toujours des mises à jour de localisation, mais onLocationChanged
ne sera jamais appelé. Vous pouvez arrêter les demandes en vérifiant si l'utilisateur a désactivé les services de localisation.
Si votre application les oblige à activer les services de localisation, vous souhaiterez afficher un message ou un toast. Malheureusement, il n'existe aucun moyen de vérifier si l'utilisateur a désactivé les services de localisation dans l'API des services de localisation de Google. Pour cela, vous devrez recourir à l'API d'Android.
Dans votre onCreate
méthode:
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;
Et utilisez le locationEnabled
drapeau dans votre onConnected
méthode comme ceci:
if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}
METTRE À JOUR
Le document est mis à jour, LocationClient est supprimé et l'API prend en charge l'activation du GPS en un seul clic dans la boîte de dialogue:
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.
}
}
}
});
Lien https://developer.android.com/training/location/change-location-settings#prompt
Nouveau client d'emplacement: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
Il est recommandé de passer par https://developer.android.com/training/location avant d'effectuer des tâches de localisation.