Lokalizacja użytkownika na Androidzie
Pobieranie lokalizacji użytkownika w systemie Android jest nieco mniej proste niż w systemie iOS. Aby rozpocząć zamieszanie, możesz to zrobić na dwa zupełnie różne sposoby. Pierwsza korzysta z interfejsów API systemu Android od android.location.LocationListener
, a druga korzysta z interfejsów API usług Google Play com.google.android.gms.location.LocationListener
. Przejdźmy przez oba z nich.
Interfejs API lokalizacji systemu Android
Interfejsy API lokalizacji systemu Android używają trzech różnych dostawców do pobierania lokalizacji -
LocationManager.GPS_PROVIDER
- Ten dostawca określa lokalizację za pomocą satelitów. W zależności od warunków ten dostawca może trochę potrwać, aby zwrócić poprawkę lokalizacji.
LocationManager.NETWORK_PROVIDER
- Ten dostawca określa lokalizację na podstawie dostępności wieży komórkowej i punktów dostępu Wi-Fi. Wyniki są pobierane za pomocą wyszukiwania sieciowego.
LocationManager.PASSIVE_PROVIDER
- Ten dostawca zwróci lokalizacje wygenerowane przez innych dostawców. Biernie otrzymujesz aktualizacje lokalizacji, gdy inne aplikacje lub usługi o nie żądają, bez konieczności samodzielnego żądania lokalizacji.
Istotą jest to, że pojawi się przedmiot LocationManager
z systemu, wdrożenia LocationListener
i nazwać requestLocationUpdates
na LocationManager
.
Oto fragment kodu:
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);
Przewodnik API Google dotyczący strategii lokalizacjiładnie wyjaśnia kod. Ale wspominają również, że w większości przypadków uzyskasz lepszą wydajność baterii, a także bardziej odpowiednią dokładność, używając zamiast tego interfejsu API usług lokalizacyjnych Google . Teraz zaczyna się zamieszanie!
- Interfejs API usług lokalizacyjnych Google
Interfejs API usług lokalizacyjnych Google jest częścią pakietu APK usług Google Play ( tutaj opisano , jak go skonfigurować ). Są zbudowane w oparciu o API Androida. Te interfejsy API zapewniają „dostawcę lokalizacji połączonej” zamiast dostawców wymienionych powyżej. Ten dostawca automatycznie wybiera bazowego dostawcę na podstawie dokładności, zużycia baterii itp. Jest szybki, ponieważ uzyskujesz lokalizację z usługi ogólnosystemowej, która stale ją aktualizuje. Możesz też korzystać z bardziej zaawansowanych funkcji, takich jak geofencing.
Aby korzystać z usług lokalizacyjnych Google, Twoja aplikacja musi łączyć się z GooglePlayServicesClient
. Aby połączyć się z klientem, Twoja aktywność (lub fragment, lub coś takiego) musi zostać zaimplementowana GooglePlayServicesClient.ConnectionCallbacks
i GooglePlayServicesClient.OnConnectionFailedListener
interfejsy. Oto przykładowy kod:
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
}
- Dlaczego jest
locationClient.getLastLocation()
null?
locationClient.getLastLocation()
Dostaje ostatnią znaną lokalizację z klientem. Jednak dostawca lokalizacji połączonej będzie utrzymywał lokalizację w tle tylko wtedy, gdy jest z nią połączony co najmniej jeden klient. Gdy pierwszy klient połączy się, natychmiast spróbuje uzyskać lokalizację. Jeśli Twoja aktywność jest pierwszym klientem, który się połączy i dzwonisz getLastLocation()
od razu onConnected()
, to może nie wystarczyć czasu na pojawienie się pierwszej lokalizacji. To spowoduje, location
że będziesz null
.
Aby rozwiązać ten problem, musisz poczekać (nieokreślony), aż dostawca otrzyma lokalizację, a następnie zadzwonić getLastLocation()
, co jest niemożliwe do ustalenia . Inną (lepszą) opcją jest zaimplementowanie com.google.android.gms.location.LocationListener
interfejsu do otrzymywania okresowych aktualizacji lokalizacji (i wyłączanie go po otrzymaniu pierwszej aktualizacji).
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!!!
}
W tym kodzie sprawdzasz, czy klient ma już ostatnią lokalizację (w onConnected
). Jeśli nie, prosisz o aktualizacje lokalizacji i wyłączasz żądania (w onLocationChanged()
oddzwonieniu), gdy tylko otrzymasz aktualizację.
Pamiętaj, że locationClient.requestLocationUpdates(locationRequest, this);
musi znajdować się w onConnected
wywołaniu zwrotnym, w przeciwnym razie otrzymasz wiadomość, IllegalStateException
ponieważ będziesz próbować zażądać lokalizacji bez połączenia z klientem usług Google Play.
- Użytkownik wyłączył usługi lokalizacyjne
Często użytkownik miałby wyłączone usługi lokalizacyjne (aby oszczędzać baterię lub ze względów prywatności). W takim przypadku powyższy kod nadal będzie żądał aktualizacji lokalizacji, ale onLocationChanged
nigdy nie zostanie wywołany. Możesz zatrzymać żądania, sprawdzając, czy użytkownik wyłączył usługi lokalizacyjne.
Jeśli Twoja aplikacja wymaga od nich włączenia usług lokalizacyjnych, zechcesz wyświetlić wiadomość lub toast. Niestety nie ma możliwości sprawdzenia, czy użytkownik wyłączył usługi lokalizacyjne w interfejsie API usług lokalizacyjnych Google. W tym celu będziesz musiał wrócić do interfejsu API Androida.
W Twojej onCreate
metodzie:
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;
I użyj locationEnabled
flagi w swojej onConnected
metodzie w następujący sposób:
if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
locationClient.requestLocationUpdates(locationRequest, this);
}
AKTUALIZACJA
Dokument jest aktualizowany, LocationClient jest usuwany, a interfejs API umożliwia włączenie GPS jednym kliknięciem w oknie dialogowym:
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.
}
}
}
});
Połącz https://developer.android.com/training/location/change-location-settings#prompt
Nowy klient lokalizacji: FusedLocationProviderClient
private FusedLocationProviderClient fusedLocationClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
}
Zaleca się, aby przed wykonaniem jakichkolwiek zadań lokalizacyjnych przejść przez stronę https://developer.android.com/training/location .