Problem:
Uzyskiwanie bieżącej lokalizacji użytkownika w ramach progu JAK NAJSZYBCIEJ, a jednocześnie oszczędzanie baterii.
Dlaczego problem jest problemem:
Po pierwsze, Android ma dwóch dostawców; sieć i GPS. Czasami sieć jest lepsza, a czasem GPS jest lepszy.
Przez „lepszy” rozumiem stosunek prędkości do dokładności.
Jestem gotów poświęcić kilka metrów dokładności, jeśli mogę uzyskać lokalizację niemal natychmiast i bez włączania GPS.
Po drugie, jeśli poprosisz o aktualizacje w celu zmiany lokalizacji, nic nie zostanie wysłane, jeśli bieżąca lokalizacja jest stabilna.
Google ma przykład określania „najlepszej” lokalizacji tutaj: http://developer.android.com/guide/topics/location/obtaining-user-location.html#BestEstimate
Ale myślę, że nie jest tak blisko, jak powinien /możliwe.
Jestem trochę zdezorientowany, dlaczego Google nie ma znormalizowanego interfejsu API dla lokalizacji, programista nie powinien dbać o to, skąd pochodzi lokalizacja, powinieneś po prostu określić, co chcesz, a telefon powinien wybrać dla Ciebie.
W czym potrzebuję pomocy:
Muszę znaleźć dobry sposób na określenie „najlepszej” lokalizacji, może za pomocą heurystyki lub innej biblioteki innej firmy.
Nie oznacza to, że należy wybrać najlepszego dostawcę!
Prawdopodobnie skorzystam ze wszystkich dostawców i wybiorę najlepszych z nich.
Tło aplikacji:
Aplikacja będzie zbierać lokalizację użytkownika w ustalonych odstępach czasu (powiedzmy co około 10 minut) i wysyła ją na serwer.
Aplikacja powinna oszczędzać jak najwięcej baterii, a lokalizacja powinna mieć dokładność X (50-100?).
Celem jest później możliwość wykreślenia ścieżki użytkownika w ciągu dnia na mapie, więc potrzebuję do tego wystarczającej dokładności.
Różne:
Jak myślisz, jakie są rozsądne wartości pożądanych i akceptowanych dokładności?
Używałem 100 m zgodnie z akceptacją i 30 m zgodnie z życzeniem. Czy to zbyt wiele pytań?
Chciałbym móc później nakreślić ścieżkę użytkownika na mapie.
Czy 100m dla pożądanego i 500m dla zaakceptowanego jest lepsze?
Poza tym, teraz mam włączony GPS na maksymalnie 60 sekund na aktualizację lokalizacji. Czy jest to zbyt krótkie, aby uzyskać lokalizację, jeśli przebywasz w pomieszczeniu z dokładnością do 200 m?
To jest mój obecny kod, każda opinia jest mile widziana (poza brakiem sprawdzania błędów, którym jest TODO):
protected void runTask() {
final LocationManager locationManager = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER));
updateBestLocation(locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
if (getLocationQuality(bestLocation) != LocationQuality.GOOD) {
Looper.prepare();
setLooper(Looper.myLooper());
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
updateBestLocation(location);
if (getLocationQuality(bestLocation) != LocationQuality.GOOD)
return;
// We're done
Looper l = getLooper();
if (l != null) l.quit();
}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
Log.i("LocationCollector", "Fail");
Looper l = getLooper();
if (l != null) l.quit();
}
};
// Register the listener with the Location Manager to receive
// location updates
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000, 1, locationListener,
Looper.myLooper());
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1,
locationListener, Looper.myLooper());
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
Looper l = getLooper();
if (l != null) l.quit();
// Log.i("LocationCollector",
// "Stopping collector due to timeout");
}
}, MAX_POLLING_TIME);
Looper.loop();
t.cancel();
locationManager.removeUpdates(locationListener);
setLooper(null);
}
if (getLocationQuality(bestLocation) != LocationQuality.BAD)
sendUpdate(locationToString(bestLocation));
else Log.w("LocationCollector", "Failed to get a location");
}
private enum LocationQuality {
BAD, ACCEPTED, GOOD;
public String toString() {
if (this == GOOD) return "Good";
else if (this == ACCEPTED) return "Accepted";
else return "Bad";
}
}
private LocationQuality getLocationQuality(Location location) {
if (location == null) return LocationQuality.BAD;
if (!location.hasAccuracy()) return LocationQuality.BAD;
long currentTime = System.currentTimeMillis();
if (currentTime - location.getTime() < MAX_AGE
&& location.getAccuracy() <= GOOD_ACCURACY)
return LocationQuality.GOOD;
if (location.getAccuracy() <= ACCEPTED_ACCURACY)
return LocationQuality.ACCEPTED;
return LocationQuality.BAD;
}
private synchronized void updateBestLocation(Location location) {
bestLocation = getBestLocation(location, bestLocation);
}
// Pretty much an unmodified version of googles example
protected Location getBestLocation(Location location,
Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return location;
}
if (location == null) return currentBestLocation;
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return location;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return currentBestLocation;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and
// accuracy
if (isMoreAccurate) {
return location;
} else if (isNewer && !isLessAccurate) {
return location;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
return location;
}
return bestLocation;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
źródło
Odpowiedzi:
Wygląda na to, że kodujemy tę samą aplikację ;-)
Oto moja obecna implementacja. Wciąż jestem w fazie testów beta mojej aplikacji do przesyłania GPS, więc może być wiele możliwych ulepszeń. ale wydaje się, że do tej pory działało całkiem dobrze.
Edycja: tutaj jest część, która żąda okresowych aktualizacji od dostawców lokalizacji:
Rzeczy do rozważenia:
nie żądaj zbyt często aktualizacji GPS, powoduje to wyczerpanie baterii. Obecnie używam 30 minut jako domyślnej dla mojej aplikacji.
dodaj opcję „minimalna odległość do ostatniej znanej lokalizacji”. bez tego punkty będą „przeskakiwać”, gdy GPS nie będzie dostępny, a lokalizacja zostanie triangulowana z wież komórkowych. lub możesz sprawdzić, czy nowa lokalizacja jest poza wartością dokładności z ostatniej znanej lokalizacji.
źródło
Aby wybrać odpowiedniego dostawcę lokalizacji dla swojej aplikacji, możesz użyć obiektów Criteria :
Zapoznaj się z dokumentacją requestLocationUpdates, aby uzyskać więcej informacji na temat uwzględnienia argumentów:
Więcej myśli
Criteria.ACCURACY_HIGH
kryterium powinno dać błędy poniżej 100m, co nie jest tak dobry jak GPS może być, ale pasuje do Twoich potrzeb.źródło
Criteria
ale co jeśli najnowsza lokalizacja sieci jest niesamowita (może wiedzieć przez Wi-Fi) i nie zajmuje czasu ani baterii, aby ją zdobyć (getLastKnown), wówczas kryteria prawdopodobnie zignorują to i zwrócą GPS. Nie mogę uwierzyć, że Google utrudniło to programistom.Odpowiadając na dwa pierwsze punkty :
GPS zawsze zapewni dokładniejszą lokalizację, jeśli jest włączona i jeśli nie ma wokół niej grubych ścian .
Jeśli lokalizacja się nie zmieniła, możesz wywołać getLastKnownLocation (String) i natychmiast pobrać lokalizację.
Stosując alternatywne podejście :
Możesz spróbować użyć identyfikatora komórki lub wszystkich sąsiednich komórek
Następnie możesz odnieść się do lokalizacji komórki za pomocą kilku otwartych baz danych (np. Http://www.location-api.com/ lub http://opencellid.org/ )
Strategia polegałaby na odczytaniu listy identyfikatorów wież podczas czytania lokalizacji. Następnie w kolejnym zapytaniu (10 minut w aplikacji) przeczytaj je ponownie. Jeśli przynajmniej niektóre wieże są takie same, można z niego bezpiecznie korzystać
getLastKnownLocation(String)
. Jeśli nie, poczekaj naonLocationChanged()
. Pozwala to uniknąć potrzeby bazy danych strony trzeciej dla lokalizacji. Możesz także wypróbować to podejście .źródło
To jest moje rozwiązanie, które działa całkiem dobrze:
źródło
Dokładność lokalizacji zależy głównie od zastosowanego dostawcy lokalizacji:
Jeśli szukasz dokładności, jedyną opcją jest GPS.
Czytałem artykuł bardzo dobrze poinformowany o tym tutaj .
Jeśli chodzi o limit czasu GPS - 60 sekund powinno wystarczyć, aw większości przypadków nawet za dużo. Myślę, że 30 sekund jest OK, a czasem nawet mniej niż 5 sekund ...
jeśli potrzebujesz tylko jednej lokalizacji, sugeruję, że w twojej
onLocationChanged
metodzie, po otrzymaniu aktualizacji wyrejestrujesz słuchacza i unikniesz niepotrzebnego korzystania z GPS.źródło
Obecnie używam, ponieważ jest to godne zaufania, aby uzyskać lokalizację i obliczać odległość dla mojej aplikacji ...... używam tego do mojej aplikacji taksówkowej.
użyj interfejsu API fusion opracowanego przez programistę Google z fuzją czujnika GPS, magnetometru, akcelerometru, a także za pomocą Wi-Fi lub lokalizacji komórki, aby obliczyć lub oszacować lokalizację. Jest również w stanie dokładnie aktualizować lokalizację również w budynku. w celu uzyskania szczegółowych informacji przejdź do linku https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi
źródło
Przeszukałem Internet w poszukiwaniu zaktualizowanej (w ubiegłym roku) odpowiedzi, używając najnowszych metod pobierania lokalizacji sugerowanych przez Google (aby użyć FusedLocationProviderClient). W końcu wylądowałem na tym:
https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates
Stworzyłem nowy projekt i skopiowałem większość tego kodu. Bum. To działa. I myślę, że bez żadnych przestarzałych linii.
Ponadto symulator nie wydaje lokalizacji GPS, o której wiem. Dotarło aż do zgłoszenia tego w dzienniku: „Wszystkie ustawienia lokalizacji są spełnione”.
I na koniec, jeśli chcesz wiedzieć (ja to zrobiłem), NIE potrzebujesz klucza API map Google z konsoli programisty Google, jeśli wszystko, czego potrzebujesz, to lokalizacja GPS.
Przydatny jest także ich samouczek. Chciałem jednak pełnego samouczka / przykładowego kodu i tego. Ich samouczek kumuluje się, ale jest mylący, gdy jesteś w tym nowy, ponieważ nie wiesz, jakie elementy potrzebujesz z wcześniejszych stron.
https://developer.android.com/training/location/index.html
I na koniec pamiętaj takie rzeczy:
Nie tylko musiałem zmodyfikować mainActivity.Java. Musiałem także zmodyfikować Strings.xml, androidmanifest.xml ORAZ prawidłowy build.gradle. A także twoja aktywność_Main.xml (ale ta część była dla mnie łatwa).
Musiałem dodać takie zależności: implementacja „com.google.android.gms: play-services-location: 11.8.0” i zaktualizować ustawienia mojego zestawu SDK studia Android, aby uwzględnić usługi Google Play. (wygląd ustawień plików ustawienia systemowe Android SDK Narzędzia SDK sprawdź usługi Google Play).
aktualizacja: symulator Androida zdawał się uzyskiwać lokalizację i zdarzenia zmiany lokalizacji (kiedy zmieniłem wartość w ustawieniach karty SIM). Ale moje najlepsze i pierwsze wyniki były na rzeczywistym urządzeniu. Prawdopodobnie najłatwiej jest przetestować na rzeczywistych urządzeniach.
źródło
Niedawno przebudowano, aby uzyskać lokalizację kodu, poznać kilka dobrych pomysłów, a na koniec udało się uzyskać stosunkowo idealną bibliotekę i wersję demonstracyjną.
@ Odpowiedź Gryphiusa jest dobra
Pełna implementacja: https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
1. Dzięki pomysłom @Gryphius, udostępniam również cały kod.
2. Każde żądanie uzupełnienia lokalizacji najlepiej usunąć Aktualizacje, w przeciwnym razie na pasku stanu telefonu zawsze będzie wyświetlana ikona pozycjonowania
źródło
Z mojego doświadczenia wynika, że najlepiej jest korzystać z poprawki GPS, chyba że jest ona niedostępna. Niewiele wiem o innych dostawcach lokalizacji, ale wiem, że w przypadku GPS istnieje kilka sztuczek, których można użyć, aby dać trochę dokładności w getcie. Wysokość jest często znakiem, więc możesz sprawdzić niedorzeczne wartości. Istnieje poprawka dokładności poprawek lokalizacji Androida. Również jeśli widzisz liczbę użytych satelitów, może to również wskazywać na precyzję.
Ciekawym sposobem na uzyskanie lepszego pomysłu na dokładność może być bardzo szybkie zapytanie o zestaw poprawek, na przykład ~ 1 / s przez 10 sekund, a następnie spanie przez minutę lub dwie. Jedna rozmowa, w której byłem, doprowadziła do przekonania, że niektóre urządzenia z Androidem i tak to zrobią. Następnie usunąłbyś wartości odstające (słyszałem wspomniany tutaj filtr Kalmana) i zastosowałeś strategię centrowania, aby uzyskać pojedynczą poprawkę.
Oczywiście głębokość, którą tu osiągniesz, zależy od tego, jak ciężkie są twoje wymagania. Jeśli masz szczególnie surowe wymagania, aby uzyskać NAJLEPSZĄ możliwą lokalizację, myślę, że przekonasz się, że lokalizacja GPS i sieci są tak podobne jak jabłka i pomarańcze. Również GPS może się znacznie różnić od urządzenia do urządzenia.
źródło
Skyhook (http://www.skyhookwireless.com/) ma dostawcę lokalizacji, który jest znacznie szybszy niż standardowy oferowany przez Google. To może być to, czego szukasz. Nie jestem z nimi związany.
źródło