Como desarrollador de SpeedView: velocímetro GPS para Android, debo haber probado todas las soluciones posibles a este problema, todas con el mismo resultado negativo. Reiteremos lo que no funciona:
- onStatusChanged () no se llama en Eclair y Froyo.
- Contar simplemente todos los satélites disponibles es, por supuesto, inútil.
- Verificar si alguno de los satélites devuelve verdadero para usedInFix () tampoco es muy útil. El sistema claramente pierde la solución, pero sigue informando que todavía hay varios sats que se utilizan en él.
Así que esta es la única solución funcional que encontré y la que realmente uso en mi aplicación. Digamos que tenemos esta clase simple que implementa 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;
}
}
}
Bien, ahora en onLocationChanged () agregamos lo siguiente:
@Override
public void onLocationChanged(Location location) {
if (location == null) return;
mLastLocationMillis = SystemClock.elapsedRealtime();
mLastLocation = location;
}
Y eso es. Básicamente, esta es la línea que lo hace todo:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000
Puede ajustar el valor de milisegundos, por supuesto, pero le sugiero que lo configure alrededor de 3-5 segundos.
Esto realmente funciona y aunque no he mirado el código fuente que dibuja el ícono del GPS nativo, esto se acerca a replicar su comportamiento. Espero que esto ayude a alguien.
mLastLocationMillis
fue configurado por una fuente distinta al GPS? El sistema afirmaría que esoisGPSFix
es cierto, pero en realidad es cualquier solución (tal vez una de la red telefónica)El icono de GPS parece cambiar su estado según los intentos de transmisión recibidos. Puede cambiar su estado usted mismo con los siguientes ejemplos de código:
Notifique que el GPS se ha habilitado:
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE"); intent.putExtra("enabled", true); sendBroadcast(intent);
Notifique que el GPS está recibiendo arreglos:
Intent intent = new Intent("android.location.GPS_FIX_CHANGE"); intent.putExtra("enabled", true); sendBroadcast(intent);
Notifique que el GPS ya no recibe reparaciones:
Intent intent = new Intent("android.location.GPS_FIX_CHANGE"); intent.putExtra("enabled", false); sendBroadcast(intent);
Notifique que el GPS se ha desactivado:
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE"); intent.putExtra("enabled", false); sendBroadcast(intent);
Código de ejemplo para registrar el receptor a los intents:
// 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);
Al recibir estos intentos de transmisión, puede notar los cambios en el estado del GPS. Sin embargo, solo se le notificará cuando cambie el estado. Por lo tanto, no es posible determinar el estado actual usando estos intentos.
fuente
nuevo miembro, así que desafortunadamente no puedo comentar o votar, sin embargo, la publicación anterior de Stephen Daye fue la solución perfecta para el mismo problema con el que he estado buscando ayuda.
una pequeña alteración en la siguiente línea:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
a:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < (GPS_UPDATE_INTERVAL * 2);
Básicamente, como estoy construyendo un juego de ritmo lento y mi intervalo de actualización ya está configurado en 5 segundos, una vez que la señal del GPS se apaga durante más de 10 segundos, ese es el momento adecuado para activar algo.
saludos amigo, pasé aproximadamente 10 horas tratando de resolver esta solución antes de encontrar tu publicación :)
fuente
Bien, intentemos una combinación de todas las respuestas y actualizaciones hasta ahora y hagamos algo como esto:
ACCESS_FINE_LOCATION
permiso a tu manifiestoLocationManager
GpsStatus.Listener
que reaccione aGPS_EVENT_SATELLITE_STATUS
LocationManager
conaddGpsStatusListener
El oyente de GPS podría ser algo como esto:
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 } } }
Las API no están claras sobre cuándo y qué información de satélite y GPS se proporciona, pero creo que una idea sería ver cuántos satélites hay disponibles. Si está por debajo de tres, entonces no puede tener una solución. Si es más, entonces debería tener una solución.
Probablemente, la prueba y el error sea el camino a seguir para determinar la frecuencia con la que Android reporta información satelital y qué información
GpsSatellite
contiene cada objeto.fuente
GpsSatellite
objeto.LocationManager.requestLocationUpdates
con la configuración de tiempo y distancia establecida en 0? Eso debería enviarle correcciones de GPS tan pronto como sucedan. Si no recibe nada, lo más probable es que no tenga una solución. Puede combinar esto con el oyente de estado anterior si lo desea.Después de algunos años de trabajar con GPS en Windows Mobile, me di cuenta de que el concepto de "perder" una posición de GPS puede ser subjetivo. Para simplemente escuchar lo que le dice el GPS, agregar un NMEAListener y analizar la oración le dirá si la corrección fue "válida" o no. Consulte http://www.gpsinformation.org/dale/nmea.htm#GGA . Desafortunadamente, con algunos GPS, este valor fluctuará hacia adelante y hacia atrás incluso durante el curso normal de funcionamiento en un área de "buena posición".
Entonces, la otra solución es comparar la hora UTC de la ubicación del GPS con la hora del teléfono (convertida a UTC). Si hay una cierta diferencia de tiempo, puede asumir que perdió la posición GPS.
fuente
Tengo un problema similar mientras trabajaba en mi proyecto de maestría, parece que la respuesta de Daye informó erróneamente "no hay solución" mientras el dispositivo permanece en una ubicación estática. Modifiqué la solución un poco, lo que parece funcionar bien para mí en una ubicación estática. No sé cómo afectaría a la batería, ya que no es mi principal preocupación, pero así es como lo hice al volver a solicitar actualizaciones de ubicación cuando se agotó el tiempo de espera.
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; } } }
fuente
Bueno, reunir todos los enfoques de trabajo dará como resultado esto (también se trata de obsoletos
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) { }
Nota: esta respuesta es una combinación de las respuestas anteriores.
fuente
Si solo necesita saber si hay una solución, verifique la última ubicación conocida proporcionada por el receptor GPS y verifique el valor .getTime () para saber cuántos años tiene. Si es lo suficientemente reciente (como ... unos segundos), tiene una solución.
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();
... y finalmente compárelo con la fecha y hora actual (¡en UTC!). Si es lo suficientemente reciente, tienes una solución.
Lo hago en mi aplicación y hasta ahora todo va bien.
fuente
Puede intentar usar LocationManager.addGpsStatusListener para actualizarse cuando cambie el estado del GPS. Parece que GPS_EVENT_STARTED y GPS_EVENT_STOPPED pueden ser lo que estás buscando.
fuente
GPS_EVENT_FIRST_FIX
sonidos más cercanos.Puede que me equivoque, pero parece que la gente se está saliendo del tema
Eso se hace fácilmente con
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE); boolean gps_on = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
Para ver si tiene una solución sólida, las cosas se ponen un poco más complicadas:
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) {} };
¿Ahora cuando quieras para ver si tienes solución?
if (loc != null){ // Our location has changed at least once blah..... }
Si quieres ser elegante, siempre puedes tener un tiempo de espera usando System.currentTimeMillis () y loc.getTime ()
Funciona de manera confiable, al menos en un N1 desde 2.1.
fuente
Con LocationManager puede getLastKnownLocation () después de getBestProvider (). Esto le da un objeto Location, que tiene los métodos getAccuracy () en metros y getTime () en milisegundos UTC
¿Esto te da suficiente información?
O tal vez podría iterar sobre LocationProviders y averiguar si cada uno cumple Criterios (ACCURACY_COARSE)
fuente
tantas publicaciones ...
GpsStatus.Listener gpsListener = new GpsStatus.Listener() { public void onGpsStatusChanged(int event) { if( event == GpsStatus.GPS_EVENT_FIRST_FIX){ showMessageDialog("GPS fixed"); } } };
agregando este código, con addGpsListener ... showMessageDialog ... solo muestra una ventana de diálogo estándar con la cadena
hizo el trabajo perfectamente para mí :) muchas gracias: =) (sry por esta publicación, aún no puedo votar)
fuente
Si no necesita una actualización en el mismo instante en que se pierde la corrección, puede modificar la solución de Stephen Daye de esa manera, que tenga un método que verifique si la corrección todavía está presente.
Por lo tanto, puede verificarlo siempre que necesite algunos datos de GPS y no necesite ese GpsStatus.Listener.
Las variables "globales" son:
private Location lastKnownLocation; private long lastKnownLocationTimeMillis = 0; private boolean isGpsFix = false;
Este es el método que se llama dentro de "onLocationChanged ()" para recordar la hora de actualización y la ubicación actual. Además de que actualiza "isGpsFix":
private void handlePositionResults(Location location) { if(location == null) return; lastKnownLocation = location; lastKnownLocationTimeMillis = SystemClock.elapsedRealtime(); checkGpsFix(); // optional }
Ese método se llama siempre que necesito saber si hay una corrección de GPS:
private boolean checkGpsFix(){ if (SystemClock.elapsedRealtime() - lastKnownLocationTimeMillis < 3000) { isGpsFix = true; } else { isGpsFix = false; lastKnownLocation = null; } return isGpsFix; }
En mi implementación, primero ejecuto checkGpsFix () y si el resultado es verdadero, uso la variable "lastKnownLocation" como mi posición actual.
fuente
Sé que es un poco tarde. Sin embargo, ¿por qué no utilizar NMEAListener si quiere saber si tiene una solución? Por lo que he leído, NMEAListener te dará las oraciones NMEA y de ahí eliges la oración correcta.
La sentencia RMC contiene el estado de corrección, que es A para OK o V para advertencia. La oración GGA contiene la calidad de corrección (0 inválida, 1 GPS o 2 DGPS)
No puedo ofrecerle ningún código Java ya que recién estoy comenzando con Android, pero he creado una biblioteca GPS en C # para aplicaciones de Windows, que estoy buscando usar con Xamarin. Solo encontré este hilo porque estaba buscando información del proveedor.
Por lo que he leído hasta ahora sobre el objeto Location, no me siento tan cómodo con métodos como getAccuracy () y hasAccuracy (). Estoy acostumbrado a extraer de las sentencias NMEA valores HDOP y VDOP para determinar qué tan precisas son mis correcciones. Es bastante común tener una solución, pero tiene un HDOP pésimo, lo que significa que su precisión horizontal no es muy buena en absoluto. Por ejemplo, sentado en su escritorio depurando con un dispositivo GPS Bluetooth externo contra una ventana, es muy probable que obtenga una solución, pero HDOP y VDOP muy deficientes. Coloque su dispositivo GPS en una maceta en el exterior o algo similar o agregue una antena externa al GPS e inmediatamente obtendrá buenos valores de HDOP y VDOP.
fuente
Tal vez sea la mejor posibilidad crear un TimerTask que establezca la ubicación recibida en un cierto valor (¿nulo?) Regularmente. Si GPSListener recibe un nuevo valor, actualizará la ubicación con los datos actuales.
Creo que sería una solución funcional.
fuente
Dices que ya probaste onStatusChanged (), pero eso funciona para mí.
Este es el método que uso (dejo que la clase maneje el 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); }
Y manejo el onStatusChanged de la siguiente manera:
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; } }
Tenga en cuenta que los métodos onProvider {Dis, En} abled () tratan de habilitar y deshabilitar el rastreo GPS por parte del usuario; no es lo que estás buscando.
fuente
Establecer el intervalo de tiempo para verificar la corrección no es una buena opción. Noté que no se llama a onLocationChanged si no se está moviendo ... lo que es comprensible ya que la ubicación no cambia :)
Mejor forma sería por ejemplo:
fuente