Android: LocationManager a usługi Google Play


151

Chcę zbudować aplikację, która koncentruje się na uzyskiwaniu aktualnej lokalizacji użytkownika, a następnie znajdowaniu interesujących miejsc (takich jak bary, restauracje itp.), Które są blisko niego za pośrednictwem interfejsu API Miejsc Google .

Po przeszukaniu sieci w poszukiwaniu miejsca, w którym można by zacząć, natknąłem się na kilka samouczków wykorzystujących tę LocationManagerklasę i kilka innych, które używają usług Google Play w celu znalezienia lokalizacji użytkownika.

Na pierwszy rzut oka obaj robią to samo, ale ponieważ jestem nowy w tej dziedzinie, trochę się pogubiłem i nie wiem, która metoda najlepiej odpowiada moim potrzebom. Więc chcę cię zapytać:

Jakie są różnice między tymi dwoma metodami znajdowania lokalizacji (jeśli takie istnieją)?


Odpowiedzi:


320

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.

  1. 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 LocationManagerz systemu, wdrożenia LocationListeneri nazwać requestLocationUpdatesna 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!

  1. 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.ConnectionCallbacksi GooglePlayServicesClient.OnConnectionFailedListenerinterfejsy. 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.LocationListenerinterfejsu 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 onConnectedwywołaniu zwrotnym, w przeciwnym razie otrzymasz wiadomość, IllegalStateExceptionponieważ 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 onLocationChangednigdy 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 onCreatemetodzie:

    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 locationEnabledflagi w swojej onConnectedmetodzie 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 .


9
Możesz użyć, SettingsApi.checkLocationSettings()aby sprawdzić, czy użytkownik włączył usługi lokalizacji (patrz tutaj: developers.google.com/android/reference/com/google/android/gms/… ).
kaolick

3
LocationClient już nie istnieje. Aby uzyskać zaktualizowany i przejrzysty przewodnik po lokalizacji, sprawdź ten artykuł: blog.teamtreehouse.com/beginners-guide-location-android
lm2a

1
I strona szkoleniowa z przykładem SettingsApi: developer.android.com/training/location/ ...
androidguy

2
Możesz również utworzyć ogrodzenie geograficzne za pomocą LocationManager! Czy interfejs API połączonej lokalizacji działa na urządzeniach, które nie mają usług Google Play?
Muhammad Babar

To może być kolejny lepszy sposób na sprawdzenie statusu włączenia / wyłączenia GPS fun isLocationEnabled(context: Context): Boolean { val locationMode: Int try { locationMode = Settings.Secure.getInt( context.contentResolver, Settings.Secure.LOCATION_MODE ) } catch (e: SettingNotFoundException) { e.printStackTrace() return false } return locationMode != Settings.Secure.LOCATION_MODE_OFF }
Wahib Ul Haq

32

Z mojego doświadczenia wynika, że ​​„bardziej odpowiednia dokładność” nie oznacza w żaden sposób lepszej. O ile czegoś nie brakuje, jeśli chcesz mieć pewność, że używany jest GPS, LocationManager jest jedynym sposobem. Śledzimy pojazdy za pomocą naszej aplikacji i znowu, jeśli czegoś nie brakuje, Usługi Google Play dość często udostępniają bardzo niedokładne lokalizacje.


2
Tak, z mojego doświadczenia wynika, że ​​usługi Google Play czasami podają niedokładną lokalizację.
VY

2
Tak, interfejs API usług lokalizacyjnych Google Play może podawać bardzo mylące informacje o lokalizacji. Modemy Wi-Fi są przenoszone, modemy Wi-Fi są aktualizowane za pomocą nieprawidłowych informacji o lokalizacji (tj. Jeśli lokalizacja jest sfałszowana przez urządzenie z systemem Android, które aktualizuje lokalizację modemu Wi-Fi) i istnieje wiele innych okoliczności, które mogą powodować nieprawidłowe dane lokalizacji z triangulacji modemu Wi-Fi. We wszystkich naszych aplikacjach, w których dokładna lokalizacja jest obowiązkowa, używamy tylko GPS.
user1608385

27

Należy użyć interfejsu API lokalizacji usług Google Play zamiast LocationManager. Według dokumentów:

Interfejsy API lokalizacji usług Google Play są preferowane w stosunku do interfejsów API lokalizacji platformy Android (android.location) jako sposób na dodanie rozpoznawania lokalizacji do aplikacji. Jeśli obecnie korzystasz z interfejsów API lokalizacji platformy Android, zdecydowanie zalecamy jak najszybsze przejście na interfejsy API lokalizacji usług Google Play.

O tym, dlaczego się przełączyć, Google mówi tak:

Interfejs API usług lokalizacyjnych Google, część usług Google Play, zapewnia bardziej wydajną strukturę wysokiego poziomu, która automatycznie obsługuje dostawców lokalizacji, ruch użytkowników i dokładność lokalizacji. Obsługuje również planowanie aktualizacji lokalizacji na podstawie podanych parametrów zużycia energii. W większości przypadków uzyskasz lepszą wydajność baterii, a także bardziej odpowiednią dokładność, korzystając z interfejsu API usług lokalizacyjnych.


2
Czy masz linki do tej dokumentacji, z której pochodzą te cytaty? Byłoby interesujące zobaczyć, czy Google mówi teraz coś innego.
Edward Brey

3
Oczywiście mówią to, ponieważ chcą danych o Twojej lokalizacji!
Flyview

Gdy dodasz usługi Google Play do swojej aplikacji, jeśli użytkownik zainstaluje Twoją aplikację, zostanie poproszony o „zaktualizowanie” usług Google Play w celu korzystania z Twojej aplikacji. W przypadku, gdy jego telefon jest prawie pełny (z memami WhatsApp i innymi rzeczami) lub użytkownik nie ma danych, przepraszam za ciebie mój przyjacielu
Dr Deo

2
@Flyview Yep! Lol, sposób, w jaki to mówią, sprawia, że ​​brzmi to jak magiczne rozwiązanie! Największą wadą jest to, że potrzebujesz usług Google Play na urządzeniu !!!
varun

25

Korzystam z interfejsu API usług lokalizacyjnych Google od dłuższego czasu. Ma zalety, ponieważ obejmuje złożoność posiadania kilku źródeł do określania pozycji. Jednak hermetyzuje zbyt mocno , więc gdy otrzymasz dziwną pozycję, nie masz możliwości określenia, skąd pochodzi ta dziwna pozycja.

W prawdziwym życiu pojawiło się kilka dziwacznych wartości, znajdujących się 10 kilometrów od rzeczywistej pozycji. Jedynym wyjaśnieniem jest to, że te szalone lokalizacje wynikają z błędów w bazach danych Google Wi-Fi lub NWK - błędów, które zawsze będą tam, ponieważ topologie Wi-Fi i sieci zmieniają się każdego dnia. Ale niestety (i zaskakująco) API nie daje żadnych informacji o tym, w jaki sposób została wyprowadzona indywidualna pozycja.

wprowadź opis obrazu tutaj

Pozostawia to problemy związane z koniecznością odfiltrowania dziwnych wartości w oparciu o sprawdzenie wiarygodności prędkości, przyspieszenia, łożyska itp.

... albo wróć do starego, dobrego interfejsu API i używaj tylko GPS, co postanowiłem zrobić, dopóki Google nie ulepszy połączonego API.


7

Interfejs API usług lokalizacyjnych Google , część usług Google Play, zapewnia bardziej wydajną strukturę wysokiego poziomu, która automatycznie obsługuje dostawców lokalizacji , ruch użytkowników i dokładność lokalizacji . Obsługuje również planowanie aktualizacji lokalizacji na podstawie podanych parametrów zużycia energii. W większości przypadków uzyskasz lepszą wydajność baterii , a także bardziej odpowiednią dokładność, korzystając z interfejsu API usług lokalizacyjnych.

Bardziej szczegółowe różnice między dwoma interfejsami API lokalizacji usług Google Play i API lokalizacji Android Framework można znaleźć tutaj


Użyłem Twojej odpowiedzi, aby odpowiedzieć na moje własne pytanie, czy to jest w porządku. Wielkie dzięki! stackoverflow.com/questions/39852955/…
Leniaal

@Leniaal, więc nie sądzisz, że moja odpowiedź zasługuje na uznanie?
Dhruvam Gupta

To stary dokument od 3 lat. Ale oto plus 1
Drew

5

Tak, interfejs API usług lokalizacyjnych Google Play może podawać bardzo mylące informacje o lokalizacji. Modemy Wi-Fi są przenoszone, modemy Wi-Fi są aktualizowane za pomocą nieprawidłowych informacji o lokalizacji (tj. Jeśli lokalizacja jest sfałszowana przez urządzenie z Androidem, które aktualizuje lokalizację modemu Wi-Fi) i istnieje szereg innych okoliczności, które mogą powodować nieprawidłowe dane lokalizacji z triangulacji modemu Wi-Fi. We wszystkich naszych aplikacjach, w których dokładna lokalizacja jest obowiązkowa, używamy tylko GPS.


3

Różnice między dwoma interfejsami API lokalizacji usługi Google Play i API platformy Android Framework opartymi na usłudze GPS

FusedLocationProviderClient

  1. W przypadku pierwszego pobrania lokalizacja nie może mieć wartości NULL (np .: inna aplikacja musi zaktualizować ostatnią znaną lokalizację w bazie danych usługi GoogleplayService. Jeśli jest pusta, należy obejść tę kwestię)
  2. W następnym sekwencyjnym pobieraniu używa requestLocationUpdates()metody do pobrania lokalizacji.
  3. Pobieranie lokalizacji jest oparte tylko na zmianie lokalizacji użytkownika , locationRequest.setInterval(milliseconds)a setFastestInterval(milliseconds)nie na niej
  4. Zwrócona wartość LatLng zawiera tylko 7 wartości dziesiętnych (np .: 11.9557996, 79.8234599), co jest mniej dokładne
  5. Zalecane, gdy wymagana aplikacja wymaga, aby aktualna odległość lokalizacji była znikoma (dokładność 50-100 metrów)
  6. Skuteczny w zużyciu baterii.

LocationManager Api

  1. Pobieranie lokalizacji użytkownika jest wywoływane za pomocą funkcji locationManager.requestLocationUpdates ()
  2. Pobieranie lokalizacji na podstawie zmiany lokalizacji użytkownika i odstępów czasu locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, milliseconds, mindistance, Mylocationlistener)

  3. Zwrócona wartość LatLng zawiera 14 wartości dziesiętnych (np .: 11,94574594963342 79,81166719458997) dokładne wartości lokalizacji

  4. Zalecane dla aplikacji opartych na lokalizacji, gdy wymagana jest większa dokładność nawet w metrach.
  5. Zużycie baterii jest oparte na interwale pobierania i odległości pobierania.

Hej! 1 ° to maksymalnie 111_111 metrów (20_000_000 / 180). Zatem 0,0000001 ° to 0,011 m = 1 cm. Nie wiem, gdzie potrzebujesz lepszej rozdzielczości GPS. I nawet nie wiem, jak można osiągnąć lepszą rozdzielczość GPS.
babay
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.