Posizione dell'utente su Android
Ottenere la posizione dell'utente su Android è un po 'meno semplice rispetto a iOS. Per iniziare la confusione, ci sono due modi totalmente diversi per farlo. Il primo utilizza API di Android android.location.LocationListener
e il secondo utilizza API di Google Play Services com.google.android.gms.location.LocationListener
. Analizziamo entrambi.
API di localizzazione di Android
Le API di localizzazione di Android utilizzano tre diversi provider per ottenere la posizione:
LocationManager.GPS_PROVIDER
- Questo provider determina la posizione utilizzando i satelliti. A seconda delle condizioni, questo provider potrebbe richiedere del tempo per restituire una correzione della posizione.
LocationManager.NETWORK_PROVIDER
- Questo provider determina la posizione in base alla disponibilità di cell tower e punti di accesso WiFi. I risultati vengono recuperati mediante una ricerca di rete.
LocationManager.PASSIVE_PROVIDER
- Questo fornitore restituirà le posizioni generate da altri fornitori. Ricevete passivamente gli aggiornamenti delle posizioni quando altre applicazioni o servizi li richiedono senza effettivamente richiedere le posizioni da soli.
L'essenza è che si ottiene un oggetto LocationManager
dal sistema, si implementa il LocationListener
e si chiama il requestLocationUpdates
il LocationManager
.
Ecco uno snippet di codice:
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);
Guida dell'API di Google sulle strategie di localizzazionespiega il codice abbastanza bene. Ma menzionano anche che nella maggior parte dei casi otterrai prestazioni della batteria migliori, oltre a una precisione più adeguata, utilizzando invece l' API dei servizi di localizzazione di Google . Ora inizia la confusione!
- API dei servizi di localizzazione di Google
L'API dei servizi di localizzazione di Google fa parte dell'APK di Google Play Services ( ecco come configurarlo ). Sono basati sull'API di Android. Queste API forniscono un "fornitore di posizione fusa" anziché i fornitori sopra menzionati. Questo provider sceglie automaticamente quale provider sottostante utilizzare, in base alla precisione, all'utilizzo della batteria, ecc. È rapido perché si ottiene la posizione da un servizio a livello di sistema che continua ad aggiornarlo. E puoi utilizzare funzionalità più avanzate come il geofencing.
Per utilizzare i servizi di localizzazione di Google, la tua app deve connettersi a GooglePlayServicesClient
. Per connettersi al client, la tua attività (o frammento, o giù di lì) deve implementare GooglePlayServicesClient.ConnectionCallbacks
e GooglePlayServicesClient.OnConnectionFailedListener
interfacce. Ecco un codice di esempio:
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
}
- Perché è
locationClient.getLastLocation()
nullo?
L' locationClient.getLastLocation()
ha l'ultima posizione nota da parte del cliente. Tuttavia, il fornitore della posizione fusa manterrà la posizione in background solo se almeno un client è collegato ad esso. Una volta che il primo client si connette, tenterà immediatamente di ottenere una posizione. Se la tua attività è il primo client a connettersi e chiami getLastLocation()
subito onConnected()
, potrebbe non essere il tempo sufficiente per entrare nella prima posizione. Ciò si tradurrà in location
essere null
.
Per risolvere questo problema, devi attendere (indeterminatamente) fino a quando il provider non ottiene la posizione e quindi chiamare getLastLocation()
, cosa impossibile da sapere. Un'altra opzione (migliore) è quella di implementare l' com.google.android.gms.location.LocationListener
interfaccia per ricevere periodici aggiornamenti di posizione (e spegnerlo una volta ottenuto il primo aggiornamento).
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!!!
}
In questo codice, stai verificando se il client ha già l'ultima posizione (in onConnected
). In caso contrario, stai richiedendo aggiornamenti sulla posizione e disattivando le richieste (in onLocationChanged()
richiamata) non appena ricevi un aggiornamento.
Si noti che locationClient.requestLocationUpdates(locationRequest, this);
deve essere all'interno del onConnected
callback, altrimenti si otterrà un IllegalStateException
perché si tenterà di richiedere posizioni senza connettersi al client di Google Play Services.
- L'utente ha disabilitato i servizi di localizzazione
Molte volte, l'utente avrebbe disabilitato i servizi di localizzazione (per risparmiare batteria o motivi di privacy). In tal caso, il codice in alto richiederà comunque aggiornamenti della posizione, ma onLocationChanged
non verrà mai chiamato. È possibile interrompere le richieste controllando se l'utente ha disabilitato i servizi di localizzazione.
Se la tua app richiede loro di abilitare i servizi di localizzazione, vorresti mostrare un messaggio o un brindisi. Sfortunatamente, non è possibile verificare se l'utente ha disabilitato i servizi di localizzazione nell'API dei servizi di localizzazione di Google. Per questo, dovrai ricorrere all'API di Android.
Nel tuo onCreate
metodo:
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 usa la locationEnabled
bandiera nel tuo onConnected
metodo in questo modo:
if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}
AGGIORNARE
Il documento viene aggiornato, LocationClient viene rimosso e l'API supporta l'abilitazione del GPS con un clic dalla finestra di dialogo:
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
Nuovo client di localizzazione: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
Si consiglia di consultare https://developer.android.com/training/location prima di eseguire qualsiasi attività di localizzazione.