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.LocationListenere 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 LocationManagerdal sistema, si implementa il LocationListenere si chiama il requestLocationUpdatesil 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.ConnectionCallbackse GooglePlayServicesClient.OnConnectionFailedListenerinterfacce. 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 locationessere 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.LocationListenerinterfaccia 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 onConnectedcallback, altrimenti si otterrà un IllegalStateExceptionperché 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 onLocationChangednon 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 onCreatemetodo:
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 locationEnabledbandiera nel tuo onConnectedmetodo 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.