2010-06-07 21 views
12

Edité: Estoy reescribiendo esta pregunta porque al parecer no estaba claro.Android GPS tiempo de espera

A veces, el servicio de GPS en los teléfonos con Android tarda mucho tiempo en arreglarse. A veces es rápido, a veces lleva horas. Lo sé y acepto esto.

Tengo una aplicación que hace muchas cosas. Una de las cosas que debe hacer es permitir que el usuario haga clic en un botón para enviar sus coordenadas actuales a un servidor. Lo que necesito son las coordenadas del teléfono cuando el usuario hace clic en el botón o dentro de un tiempo razonablemente corto después de eso.

Como sé que obtener una corrección de GPS no es instantáneo y sé que podría tomar minutos u horas (durante las cuales el usuario se ha movido una gran distancia), necesito programar un tiempo de espera para esta función. Para esta característica, simplemente no es aceptable cargar la ubicación del GPS del usuario tres minutos (por ejemplo) después de hacer clic en el botón. Está bien si lleva 45 segundos, no está bien si lleva 75 segundos. Está bien dar al usuario una notificación de error si la característica no logró obtener una ubicación lo suficientemente rápido.

Necesito una función para 'obtener la ubicación del GPS y enviarla al servidor, a menos que tome más de un minuto'.

Mi código original está por debajo. He cambiado algunas cosas desde que lo publiqué. He agregado un temporizador en el método onStartCommand(). Comienzo un TimerTask que después de 60 segundos llamará a mi método stop(). Al comienzo del método onLocationChanged(), cancelo TimerTask.

Mi pregunta es: ¿Es el esquema del temporizador una buena forma de implementar este tiempo de espera? ¿Hay una mejor manera?

pregunta original:

Estoy escribiendo una aplicación para Android que, entre otras cosas, tiene que enviar las coordenadas de GPS actual a un servidor cuando el usuario lo indica. Desde un menú contextual, ejecuto el servicio a continuación. El servicio es un LocationListener y solicita actualizaciones del LocationManager. Cuando obtiene una ubicación (onLocationChanged()), se elimina como un oyente y envía las coordenadas al servidor. Todo esto está funcionando.

Sin embargo, si las coordenadas de GPS no están disponibles rápidamente, mi servicio sigue funcionando hasta que se recupera. Mantiene la interfaz de usuario con un diálogo de progreso, que es molesto. Peor aún, si el usuario se ha movido desde que comenzó el servicio, las primeras coordenadas de GPS podrían estar equivocadas y la aplicación enviará datos incorrectos al servidor.

Necesito un tiempo de espera en el servicio. ¿Hay una buena manera de hacer eso? No tengo mucha experiencia con los hilos. Creo que puedo ejecutar un Runnable en el método onStartCommand() que de alguna manera contará hacia abajo 30 segundos y luego, si aún no hay un resultado de GPS, llame al método stop() de mi servicio. ¿Eso suena como la mejor manera de hacer esto?

Como alternativa, ¿es posible decir si el GPS no puede obtener una solución? ¿Cómo voy a hacer eso?

Edit: Para aclarar más, estoy buscando la mejor manera de "renunciar" a obtener una ubicación después de un período de tiempo.

public class AddCurrentLocation extends Service implements LocationListener { 

    Application app; 
    LocationManager mLocManager; 
    ProgressDialog mDialog; 

    @Override 
    public int onStartCommand(Intent intent, int arg0, int arg1) { 
     app = getApplication(); 

     // show progress dialog 
     if (app.getScreen() != null) { 
      mDialog = ProgressDialog.show(app.getScreen(), "", "Adding Location. Please wait...", true); 
     } 

     // find GPS service and start listening 
     Criteria criteria = new Criteria(); 
     criteria.setAccuracy(Criteria.ACCURACY_FINE); 
     mLocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
     String bestProvider = mLocManager.getBestProvider(criteria, true); 
     mLocManager.requestLocationUpdates(bestProvider, 2000, 0, this); 

     return START_NOT_STICKY; 
    } 

    private void stop() { 
     mLocManager.removeUpdates(this); 
     if (mDialog != null) { 
      mDialog.dismiss(); 
     } 
     stopSelf(); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     // done with GPS stop listening 
     mLocManager.removeUpdates(this); 

     sendLocation(location); // method to send info to server 
     stop(); 
    } 

    // other required methods and sendLocation() ... 

} 
+0

entonces, ¿qué hizo después de todo para resolverlo? Tengo el mismo problema. – sexitrainer

Respuesta

6

Eso no es realmente como funciona. En la mayoría de los casos, tardará todo ese tiempo en obtener una solución de GPS.Pero a partir de ese momento, cada actualización (cada 2 segundos en su código) será la posición actual de la persona. Y la primera solución que obtenga será la posición actual de la persona, por lo que los datos no estarán "desactualizados".

Otra cosa. Si está ejecutando este código en un servicio, no debe bloquear la interfaz de usuario con un diálogo de progreso y definitivamente no desde el Servicio. Esa es una pérdida de memoria esperando a suceder. Solo debe mostrar el progreso si es algo que puede tardar 5 segundos como máximo y se está ejecutando en un subproceso de la Actividad. Otra opción es mostrar el cuadro de diálogo de progreso en la barra de título, y aún así dejar que el usuario interactúe con la aplicación (razón por la cual utiliza un servicio de todos modos). Mostrar progresos durante un largo período de tiempo realmente no es tan fácil de usar. Especialmente si de alguna manera cambian la orientación (tal vez por accidente) y luego su aplicación se cuelga debido a que el servicio maneja el diálogo y tienen que comenzar de nuevo.

Eche un vistazo a Google I/O 2010 app para ver un gran ejemplo de cómo una actividad debería funcionar con un servicio. Utiliza un servicio para recuperar datos y muestra un progreso en el título mientras el servicio está trabajando. Y aún te permite hacer otras cosas en la aplicación.

+1

Gracias por su ayuda. Lo que necesito hacer es obtener una sola ubicación cuando el usuario selecciona una opción de menú contextual. Entonces, si toma 15 minutos obtener una corrección de GPS (y lo tiene en mi teléfono a veces), entonces esa posición estará desactualizada. Básicamente, quiero saber dónde estaba el usuario cuando hizo clic en el botón y si tarda demasiado (lo que sea que sea), entonces debo decirle al usuario que la función falló. En la mayoría de los casos, el usuario estará sentado mirando el teléfono para ver si funcionó. No puedo tenerlos allí sentados durante horas sin señal de GPS :) –

+0

Si ese es el caso, entonces ¿por qué no comienzas gps justo cuando la aplicación se inicia y luego cada vez que presionan el botón probablemente ya tengan una solución . Y como dije antes. Con GPS, la ubicación no estará desactualizada. Se arregla y la actualización de ubicación será la ubicación actual del teléfono. –

+0

He editado mi pregunta para que sea más clara. –

4

Scott, hay muchos factores que afectan la duración de una primera corrección, o incluso si se puede lograr una solución, siendo los obstáculos físicos más comunes entre el dispositivo y los satélites (edificios de este tipo, paredes de cañones, etc.) .

No se puede controlar el tiempo que tarda el motor de GPS para ofrecer una solución, pero se puede decir cómo su hacer, incluyendo la hora del primer punto de referencia:

locationManager.addGpsStatusListener(gpsListener); 

    // this reports on the status of the GPS engine, but does not enable additional controls 
    private static final GpsStatus.Listener gpsListener = new GpsStatus.Listener() { 
     public void onGpsStatusChanged(int event) { 
      GpsStatus gpsStatus = locationManager.getGpsStatus(null); 
      switch (event) { 
       case GpsStatus.GPS_EVENT_STARTED: 
        Log.i(TAG, "onGpsStatusChanged(): GPS started"); 
        break; 
       case GpsStatus.GPS_EVENT_FIRST_FIX: 
        Log.i(TAG, "onGpsStatusChanged(): time to first fix in ms = " + gpsStatus.getTimeToFirstFix()); 
        break; 
       case GpsStatus.GPS_EVENT_SATELLITE_STATUS: 
        // int maxSatellites = gpsStatus.getMaxSatellites(); // appears fixed at 255 
        // if (H.DEBUG) Log.d(TAG, "onGpsStatusChanged(): max sats = " + maxSatellites); 
        if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): ##,used,s/n,az,el"); 
        Iterable<GpsSatellite>satellites = gpsStatus.getSatellites(); 
        Iterator<GpsSatellite>satI = satellites.iterator(); 
        while (satI.hasNext()) { 
         GpsSatellite satellite = satI.next(); 
         if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): " + satellite.getPrn() + "," + satellite.usedInFix() + "," + satellite.getSnr() + "," + satellite.getAzimuth() + "," + satellite.getElevation()); 
         // http://en.wikipedia.org/wiki/Global_Positioning_System: the almanac consists of coarse orbit and status information for each satellite 
         // http://en.wikipedia.org/wiki/Ephemeris: the positions of astronomical objects in the sky at a given time 
         // + "," + satellite.hasAlmanac() + "," + satellite.hasEphemeris()); 
        } 
        break; 
       case GpsStatus.GPS_EVENT_STOPPED: 
        Log.i(TAG, "onGpsStatusChanged(): GPS stopped"); 
        break; 
      }  
     } 
    }; 

Eventos se generará como el motor intenta escuchar los satélites disponibles. En una prueba reciente de esto con obstáculos ligeros, encontré que tardó 22.4 segundos para obtener una solución inicial, durante la cual 24 eventos SATELLITE_STATUS informaron el acceso gradual de 8 satélites antes de que se recibieran señales suficientemente limpias para lograr la solución. Aquí está el último evento:

06-08 23: 23: 25.147, D, GPS, 22427, "onGpsStatusChanged(): ##, used, s/n, az, el" 06-08 23:23 : 25.147, D, GPS, 22427, "onGpsStatusChanged(): 2, verdadero, 26.0,57.0,73.0" 06-08 23: 23: 25.147, D, GPS, 22427, "onGpsStatusChanged(): 4, verdadero, 30.0 , 46.0,27.0 " 06-08 23: 23: 25.147, D, GPS, 22427," onGpsStatusChanged(): 5, verdadero, 19.0,144.0,25.0 " 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 9, true, 22.0,202.0,22.0" 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 10, verdadero, 17.0,109.0,32.0" 06 -08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 12, verdadero, 32.0,320.0,80.0" 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 29, cierto, 21.0,278.0,21.0 " 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 30, verdadero, 31.0,312.0,43.0" 06-08 23: 23: 25.163, D, GpsLocationProvider, 1039, TTFF: 22457 06-08 23: 23: 25.194, I, GPS, 22427, onGpsStatusChanged(): hora de la primera reparación en ms = 22457

Tenga en cuenta que en el momento de la reparación, obtendrá la ubicación actual, no donde una vez podría haber sido. Creo que junto con lo que ya tienes puedes llegar allí ahora. O bien, compruebe cómo lo hacen los profesionales here.

+0

Gracias por su ayuda. He editado mi pregunta para ser más clara. –

+0

@DJC, corrija el enlace roto a MyTracks.java. – Gili

+0

¿Qué es H en el código? – Siddhesh

-7

Sobre la base de la respuesta a Shawn, el paquete de los parámetros en JSON y enviar los objetos de JSON en el servidor

1

He estado luchando con un problema similar y recientemente cambiaron de un temporizador para un AlarmManager , que parece ser mucho más robusto. Eso puede ser excesivo para su situación (estoy usando esto para el muestreo de ubicación repetida), pero es posible que desee utilizar al menos un Handler en lugar del temporizador. (Use Handler.postDelayed.)

Cuestiones relacionadas