Jako twórca SpeedView: prędkościomierza GPS dla Androida, musiałem wypróbować każde możliwe rozwiązanie tego problemu, wszystkie z tym samym negatywnym wynikiem. Powtórzmy, co nie działa:
- onStatusChanged () nie jest wywoływany przez Eclair i Froyo.
- Zwykłe liczenie wszystkich dostępnych satelitów jest oczywiście bezużyteczne.
- Sprawdzenie, czy którykolwiek z satelitów zwraca true dla usedInFix () również nie jest zbyt pomocne. System wyraźnie gubi poprawkę, ale wciąż raportuje, że wciąż jest w nim używanych kilka satów.
Oto jedyne działające rozwiązanie, które znalazłem i to, którego faktycznie używam w mojej aplikacji. Powiedzmy, że mamy tę prostą klasę, która implementuje GpsStatus.Listener:
private class MyGPSListener implements GpsStatus.Listener {
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
if (mLastLocation != null)
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
if (isGPSFix) {
} else {
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
isGPSFix = true;
break;
}
}
}
OK, teraz w onLocationChanged () dodajemy:
@Override
public void onLocationChanged(Location location) {
if (location == null) return;
mLastLocationMillis = SystemClock.elapsedRealtime();
mLastLocation = location;
}
I to wszystko. Zasadniczo jest to linia, która robi wszystko:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000
Oczywiście możesz dostosować wartość milisekund, ale radzę ustawić ją na około 3-5 sekund.
To faktycznie działa i chociaż nie spojrzałem na kod źródłowy, który rysuje natywną ikonę GPS, zbliża się to do odtworzenia jej zachowania. Mam nadzieję, że to komuś pomoże.
mLastLocationMillis
zostało ustawione przez inne źródło niż GPS? System mógłby wtedy twierdzić, żeisGPSFix
to prawda, ale w rzeczywistości jest to jakakolwiek poprawka (może jedna z sieci telefonicznej)Ikona GPS wydaje się zmieniać swój stan zgodnie z odebranymi intencjami transmisji. Możesz samodzielnie zmienić jego stan za pomocą następujących przykładów kodu:
Powiadom, że GPS został włączony:
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE"); intent.putExtra("enabled", true); sendBroadcast(intent);
Powiadom, że GPS odbiera poprawki:
Intent intent = new Intent("android.location.GPS_FIX_CHANGE"); intent.putExtra("enabled", true); sendBroadcast(intent);
Powiadom, że GPS nie otrzymuje już poprawek:
Intent intent = new Intent("android.location.GPS_FIX_CHANGE"); intent.putExtra("enabled", false); sendBroadcast(intent);
Powiadom, że GPS został wyłączony:
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE"); intent.putExtra("enabled", false); sendBroadcast(intent);
Przykładowy kod do rejestracji odbiorcy do intencji:
// MyReceiver must extend BroadcastReceiver MyReceiver receiver = new MyReceiver(); IntentFilter filter = new IntentFilter("android.location.GPS_ENABLED_CHANGE"); filter.addAction("android.location.GPS_FIX_CHANGE"); registerReceiver(receiver, filter);
Odbierając te intencje transmisji, możesz zauważyć zmiany w stanie GPS. Jednak zostaniesz powiadomiony tylko wtedy, gdy stan się zmieni. W związku z tym nie jest możliwe określenie aktualnego stanu na podstawie tych założeń.
źródło
nowy członek, więc niestety nie mogę komentować ani głosować, jednak powyższy post Stephena Daye był idealnym rozwiązaniem tego samego problemu, z którym szukałem pomocy.
mała zmiana w następującym wierszu:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
do:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
Zasadniczo, ponieważ buduję wolną grę, a mój interwał aktualizacji jest już ustawiony na 5 sekund, gdy sygnał GPS wyłączy się przez ponad 10 sekund, jest to właściwy czas, aby coś uruchomić.
Pozdrawiam kolego, spędziłem około 10 godzin próbując rozwiązać to rozwiązanie, zanim znalazłem twój post :)
źródło
Ok, więc wypróbujmy kombinację wszystkich dotychczasowych odpowiedzi i aktualizacji i zróbmy coś takiego:
ACCESS_FINE_LOCATION
pozwolenie do manifestuLocationManager
GpsStatus.Listener
który reaguje naGPS_EVENT_SATELLITE_STATUS
LocationManager
waddGpsStatusListener
Odbiornikiem GPS może być coś takiego:
GpsStatus.Listener listener = new GpsStatus.Listener() { void onGpsStatusChanged(int event) { if (event == GPS_EVENT_SATELLITE_STATUS) { GpsStatus status = mLocManager.getGpsStatus(null); Iterable<GpsSatellite> sats = status.getSatellites(); // Check number of satellites in list to determine fix state } } }
Interfejsy API są nieco niejasne, kiedy i jakie informacje GPS i satelity są podawane, ale myślę, że pomysł polegałby na sprawdzeniu, ile satelitów jest dostępnych. Jeśli jest poniżej trzech, nie możesz znaleźć rozwiązania. Jeśli jest więcej, powinieneś mieć poprawkę.
Próba i błąd to prawdopodobnie sposób na określenie, jak często Android zgłasza informacje o satelitach i jakie informacje
GpsSatellite
zawiera każdy obiekt.źródło
GpsSatellite
obiektu.LocationManager.requestLocationUpdates
z ustawieniami czasu i odległości ustawionymi na 0? Powinno to wysyłać poprawki GPS, gdy tylko się pojawią. Jeśli nic nie otrzymujesz, najprawdopodobniej nie masz rozwiązania. Jeśli chcesz, możesz to połączyć z odbiornikiem stanu powyżej.Po kilku latach pracy z GPS na urządzeniach mobilnych z systemem Windows zdałem sobie sprawę, że koncepcja „utraty” pozycji GPS może być subiektywna. Aby po prostu posłuchać tego, co mówi GPS, dodanie NMEAListenera i przeanalizowanie zdania powie, czy poprawka była „poprawna”, czy nie. Zobacz http://www.gpsinformation.org/dale/nmea.htm#GGA . Niestety w przypadku niektórych odbiorników GPS wartość ta będzie się wahać w przód iw tył, nawet podczas normalnej pracy w obszarze „dobrego ustalenia”.
Tak więc innym rozwiązaniem jest porównanie czasu UTC lokalizacji GPS z czasem telefonu (przeliczonym na UTC). Jeśli różnią się od siebie pewną różnicą czasu, możesz założyć, że utraciłeś pozycję GPS.
źródło
napotkałem podobny problem podczas pracy nad moim projektem magisterskim, wydaje się, że odpowiedź Daye omyłkowo zgłosiła „brak poprawki”, podczas gdy urządzenie pozostaje w statycznej lokalizacji. Trochę zmodyfikowałem rozwiązanie, które wydaje mi się dobrze działać w statycznej lokalizacji. Nie wiem, jak to wpłynie na baterię, ponieważ nie jest to moim głównym zmartwieniem, ale oto jak to zrobiłem, ponownie prosząc o aktualizacje lokalizacji, gdy upłynął limit czasu naprawy.
private class MyGPSListener implements GpsStatus.Listener { public void onGpsStatusChanged(int event) { switch (event) { case GpsStatus.GPS_EVENT_SATELLITE_STATUS: if (Global.getInstance().currentGPSLocation != null) { if((SystemClock.elapsedRealtime() - mLastLocationMillis) < 20000) { if (!hasGPSFix) Log.i("GPS","Fix Acquired"); hasGPSFix = true; } else { if (hasGPSFix) { Log.i("GPS","Fix Lost (expired)"); lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, locationListener); } hasGPSFix = false; } } break; case GpsStatus.GPS_EVENT_FIRST_FIX: Log.i("GPS", "First Fix/ Refix"); hasGPSFix = true; break; case GpsStatus.GPS_EVENT_STARTED: Log.i("GPS", "Started!"); break; case GpsStatus.GPS_EVENT_STOPPED: Log.i("GPS", "Stopped"); break; } } }
źródło
Cóż, połączenie wszystkich metod pracy spowoduje to (również radzenie sobie z przestarzałymi
GpsStatus.Listener
):private GnssStatus.Callback mGnssStatusCallback; @Deprecated private GpsStatus.Listener mStatusListener; private LocationManager mLocationManager; @Override public void onCreate() { mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); if (checkPermission()) { mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_INTERVAL, MIN_DISTANCE, this); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { mGnssStatusCallback = new GnssStatus.Callback() { @Override public void onSatelliteStatusChanged(GnssStatus status) { satelliteStatusChanged(); } @Override public void onFirstFix(int ttffMillis) { gpsFixAcquired(); } }; mLocationManager.registerGnssStatusCallback(mGnssStatusCallback); } else { mStatusListener = new GpsStatus.Listener() { @Override public void onGpsStatusChanged(int event) { switch (event) { case GpsStatus.GPS_EVENT_SATELLITE_STATUS: satelliteStatusChanged(); break; case GpsStatus.GPS_EVENT_FIRST_FIX: // Do something. gpsFixAcquired(); break; } } }; mLocationManager.addGpsStatusListener(mStatusListener); } } private void gpsFixAcquired() { // Do something. isGPSFix = true; } private void satelliteStatusChanged() { if (mLastLocation != null) isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2); if (isGPSFix) { // A fix has been acquired. // Do something. } else { // The fix has been lost. // Do something. } } @Override public void onLocationChanged(Location location) { if (location == null) return; mLastLocationMillis = SystemClock.elapsedRealtime(); mLastLocation = location; } @Override public void onStatusChanged(String s, int i, Bundle bundle) { } @Override public void onProviderEnabled(String s) { } @Override public void onProviderDisabled(String s) { }
Uwaga: ta odpowiedź jest połączeniem powyższych odpowiedzi.
źródło
Jeśli chcesz tylko wiedzieć, czy istnieje poprawka, sprawdź ostatnią znaną lokalizację dostarczoną przez odbiornik GPS i sprawdź wartość .getTime (), aby wiedzieć, ile ma lat. Jeśli jest wystarczająco niedawna (np. Kilka sekund), masz rozwiązanie.
LocationManager lm = (LocationManager)context.getSystemService(LOCATION_SERVICE); Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); // Get the time of the last fix long lastFixTimeMillis = loc.getTime();
... i na koniec porównaj to z aktualną datą i czasem (w UTC!). Jeśli jest wystarczająco nowy, masz poprawkę.
Robię to w mojej aplikacji i jak na razie dobrze.
źródło
Możesz spróbować użyć LocationManager.addGpsStatusListener, aby uzyskać informacje o zmianie stanu GPS. Wygląda na to, że GPS_EVENT_STARTED i GPS_EVENT_STOPPED mogą być tym, czego szukasz.
źródło
GPS_EVENT_FIRST_FIX
dźwiękami przypominającymi dopasowanie.Może się mylę, ale wydaje się, że ludzie odchodzą od tematu
Można to łatwo zrobić
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE); boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
Aby sprawdzić, czy masz solidną poprawkę, sprawy stają się nieco trudniejsze:
public class whatever extends Activity { LocationManager lm; Location loc; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lm = (LocationManager) getSystemService(LOCATION_SERVICE); loc = null; request_updates(); } private void request_updates() { if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { // GPS is enabled on device so lets add a loopback for this locationmanager lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, locationListener); } } LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { // Each time the location is changed we assign loc loc = location; } // Need these even if they do nothing. Can't remember why. public void onProviderDisabled(String arg0) {} public void onProviderEnabled(String provider) {} public void onStatusChanged(String provider, int status, Bundle extras) {} };
Teraz, kiedy chcesz sprawdzić, czy masz poprawkę?
if (loc != null){ // Our location has changed at least once blah..... }
Jeśli chcesz być fantazyjny, zawsze możesz ustawić limit czasu za pomocą System.currentTimeMillis () i loc.getTime ()
Działa niezawodnie, przynajmniej na N1 od 2.1.
źródło
Dzięki LocationManager możesz uzyskaćLastKnownLocation () po wykonaniu metody getBestProvider (). Daje to obiekt Location, który ma metody getAccuracy () w metrach i getTime () w milisekundach UTC
Czy to daje wystarczająco dużo informacji?
A może możesz iterować przez LocationProviders i dowiedzieć się, czy każdy z nich spełnia kryteria (ACCURACY_COARSE)
źródło
tak wiele postów ...
GpsStatus.Listener gpsListener = new GpsStatus.Listener() { public void onGpsStatusChanged(int event) { if( event == GpsStatus.GPS_EVENT_FIRST_FIX){ showMessageDialog("GPS fixed"); } } };
dodanie tego kodu za pomocą addGpsListener ... showMessageDialog ... po prostu pokazuje standardowe okno dialogowe z ciągiem znaków
wykonał robotę idealnie dla mnie :) wielkie dzięki: =) (prosze za ten post, jeszcze nie moge glosowac)
źródło
Jeśli nie potrzebujesz aktualizacji natychmiast po utracie poprawki, możesz zmodyfikować rozwiązanie Stephena Daye w ten sposób, aby mieć metodę, która sprawdza, czy poprawka jest nadal obecna.
Możesz więc po prostu to sprawdzić, gdy potrzebujesz danych GPS i nie potrzebujesz tego GpsStatus.Listener.
Zmienne „globalne” to:
private Location lastKnownLocation; private long lastKnownLocationTimeMillis = 0; private boolean isGpsFix = false;
Jest to metoda wywoływana w ramach metody „onLocationChanged ()” w celu zapamiętania czasu aktualizacji i bieżącej lokalizacji. Oprócz tego aktualizuje „isGpsFix”:
private void handlePositionResults(Location location) { if(location == null) return; lastKnownLocation = location; lastKnownLocationTimeMillis = SystemClock.elapsedRealtime(); checkGpsFix(); // optional }
Ta metoda jest wywoływana za każdym razem, gdy chcę wiedzieć, czy istnieje poprawka GPS:
private boolean checkGpsFix(){ if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) { isGpsFix = true; } else { isGpsFix = false; lastKnownLocation = null; } return isGpsFix; }
W mojej implementacji najpierw uruchamiam checkGpsFix () i jeśli wynik jest prawdziwy, używam zmiennej „lastKnownLocation” jako mojej aktualnej pozycji.
źródło
Wiem, że to trochę późno. Jednak dlaczego nie skorzystać z NMEAListener, jeśli chcesz wiedzieć, czy masz poprawkę. Z tego, co przeczytałem, NMEAListener poda Ci zdania NMEA i stamtąd wybierzesz prawidłowe zdanie.
Zdanie RMC zawiera status poprawki, który jest A dla OK lub V dla ostrzeżenia. Zdanie GGA zawiera poprawkę jakości (0 nieważne, 1 GPS lub 2 DGPS)
Nie mogę zaoferować Ci żadnego kodu java, ponieważ dopiero zaczynam od Androida, ale zrobiłem bibliotekę GPS w C # dla aplikacji Windows, której chcę używać z Xamarin. Trafiłem na ten wątek tylko dlatego, że szukałem informacji o dostawcy.
Z tego, co do tej pory przeczytałem o obiekcie Location, nie czuję się dobrze w metodach takich jak getAccuracy () i hasAccuracy (). Jestem przyzwyczajony do wyodrębniania ze zdań NMEA wartości HDOP i VDOP, aby określić, jak dokładne są moje poprawki. Dość często ma się poprawkę, ale ma kiepski HDOP, co oznacza, że twoja dokładność pozioma nie jest wcale dobra. Na przykład siedząc przy biurku podczas debugowania za pomocą zewnętrznego urządzenia Bluetooth GPS mocno przy oknie, prawdopodobnie otrzymasz poprawkę, ale bardzo słabe HDOP i VDOP. Umieść urządzenie GPS w doniczce na zewnątrz lub w czymś podobnym lub dodaj zewnętrzną antenę do GPS, a natychmiast uzyskasz dobre wartości HDOP i VDOP.
źródło
Być może jest to najlepsza możliwość, aby utworzyć TimerTask, które regularnie ustawia otrzymaną lokalizację na określoną wartość (null?). Jeśli GPSListener otrzyma nową wartość, zaktualizuje lokalizację aktualnymi danymi.
Myślę, że byłoby to działające rozwiązanie.
źródło
Mówisz, że próbowałeś już StatusChanged (), ale to działa dla mnie.
Oto metoda, której używam (pozwoliłem samej klasie obsługiwać onStatusChanged):
private void startLocationTracking() { final int updateTime = 2000; // ms final int updateDistance = 10; // meter final Criteria criteria = new Criteria(); criteria.setCostAllowed(false); criteria.setAccuracy(Criteria.ACCURACY_FINE); final String p = locationManager.getBestProvider(criteria, true); locationManager.requestLocationUpdates(p, updateTime, updateDistance, this); }
I obsługuję onStatusChanged w następujący sposób:
void onStatusChanged(final String provider, final int status, final Bundle extras) { switch (status) { case LocationProvider.OUT_OF_SERVICE: if (location == null || location.getProvider().equals(provider)) { statusString = "No Service"; location = null; } break; case LocationProvider.TEMPORARILY_UNAVAILABLE: if (location == null || location.getProvider().equals(provider)) { statusString = "no fix"; } break; case LocationProvider.AVAILABLE: statusString = "fix"; break; } }
Zwróć uwagę, że metody onProvider {Dis, En} abled () dotyczą włączania i wyłączania śledzenia GPS przez użytkownika; nie to, czego szukasz.
źródło
Ustawienie odstępu czasu w celu sprawdzenia poprawności nie jest dobrym wyborem. Zauważyłem, że onLocationChanged nie jest wywoływany, jeśli się nie ruszasz .. co jest zrozumiałe, ponieważ lokalizacja się nie zmienia :)
Lepszym sposobem byłoby na przykład:
źródło