2012-06-27 18 views
5

estoy corriendo un servicio en segundo plano que lee localización GPS/red y necesita hacer lo siguiente:Servicio Android y repetitiva tarea se ejecuta en las discusiones

  • ejecución en segundo plano y sin interrupciones en el reinicio de aplicaciones y mantenerlo viva tanto como sea posible sin que se mató (Esto se soluciona con la ayuda de comentario abajo de Merlin)

  • en una nueva ubicación recibido, llamar a un servicio web y enviar la ubicación de lectura

  • tienen una repeti tarea activa cada 60 segundos y reenviar la última ubicación al servicio web. Esto ayudará en caso de que el usuario permanezca en la misma posición.

Hay algunas cosas que he considerado y no estoy seguro de haber entendido bien. El servicio se ejecuta en el mismo hilo que la aplicación principal, por lo que enviar la ubicación al servidor en el mismo subproceso que el subproceso de la interfaz de usuario puede desencadenar bloqueos de UI y esto no es bueno. Además, no estoy seguro si los oyentes de GPS/Red tienen sus propios hilos o usan el mismo hilo que la aplicación.

Aquí es un código acortada del servicio para hacer las cosas más claras:

public class GPSLoggerService extends Service { 
@Override 
public void onCreate() { 
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 

    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 50, locationListenerNetwork); 
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 50, locationListenerGps); 

    scheduleTaskExecutor = Executors.newScheduledThreadPool(5); 
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() { 
     @Override 
     public void run() { 
       updateLocation(lastLocation); 
     }, 60, 60, TimeUnit.SECONDS); 

    return START_STICKY; 
} 

LocationListener locationListenerGps = new LocationListener() { 
    @Override 
    public void onLocationChanged(Location location) { 
     updateLocation(location); 
    } 
... 
}  

LocationListener locationListenerNetwork = new LocationListener() { 
    @Override 
    public void onLocationChanged(Location location) { 
     updateLocation(location); 
    } 
... 
} 

private void updateLocation(Location readLocation) { 
    //web service call 
    String response = WebServiceCalls.updateLocation(readLocation); 

    //log data in a local Sqlite database 
    saveLocation(readLocation) 
} 

Mi principal preocupación es cómo manejar la llamada UpdateLocation y tenerlo en un hilo separado del hilo principal aplicación. The scheduleTaskExecutor Creo que no es el camino a seguir. A veces, incluso después de llamar a stopService(), el servicio permanece activo, incluso si le digo a TaskExecutor que se apague. No puedo encontrar otra explicación por la cual el servicio no se detenga. Recapitulando: necesito enviar la ubicación cada vez que los oyentes reciben una nueva ubicación y volver a enviarla cada 60 segundos. También necesito poder detener el servicio rápidamente con la cancelación de hilos activos.

¿Cómo me recomendaría para manejar mi caso?

+0

Qué se necesita para iniciarlo pegajosa? – Merlin

Respuesta

0

Para evitar que su servicio se destruya, puede comenzar su servicio como foreground service.

Y después de obtener una ubicación del método onLocationChanged(), puede usar un asynctask para enviar una ubicación al servicio web para que no bloquee su UI.

Editar

  1. Puede establecer el tiempo mínimo y la distancia mínima recorrida en sus requestLocationUpdates método. Así que no creo que deba usar la tarea del planificador para enviar la ubicación al servidor. Según el argumento sobre el tiempo mínimo y la distancia mínima, el administrador de la ubicación comprobará la ubicación.Si hay una ubicación modificada, llamará al método LocationChanged() con la nueva ubicación. Ahora, para su solución sobre el usuario, permanece en la misma posición. puede cambiar un poco de lógica al lado del servidor como si hubiera una diferencia de 1 hora entre dos ubicaciones sucesivas ubicación1 y ubicación2 significa que el usuario se ha quedado 1 hora en ubicación1.

  2. Puede usar una única clase LocationListener para escuchar la ubicación de GPS y de RED.

  3. Cuando obtiene la ubicación en el método onLocationChanged(), puede enviar esa ubicación mediante una asynctask.
  4. Después de obtener la ubicación, puede guardar esa ubicación en la preferencia o base de datos para verificar si el GPS y el proveedor de red le envían la misma ubicación. Si realiza un seguimiento, puede guardar su llamada webAPI para poder guardar una parte del batería.
+0

Como puede ver, hay lecturas tanto de GPS como de red y también se envían a tiempo. Esto significa que debería tener 3 llamadas para la asynctask al mismo tiempo. ¿Cómo los cancelaría? – Alin

+0

Debo enviar la posición incluso si el conductor se mantiene en la misma posición ya que esto forma parte de las especificaciones del proyecto. Entonces no puedo cambiar esto Sin embargo, no veo asynctask como una buena solución para mi caso. Imagine que puedo recibir una nueva ubicación cada 1 segundo si el usuario está conduciendo. Esto significa que cada 1 segundo debo disparar la asynctask para poder tener entre 2 y 3 tareas en ejecución ... ¿Cómo puedo cancelarlas cuando se detiene el servicio? – Alin

+0

Solo piense en el caso que desea enviar la ubicación cada 1 segundos. Desea manejar su llamada webAPI cada 1 segundo (no todas las veces, pero en el caso de una ubicación sucesiva modificada). Si cancela la última y actualiza la nueva, entonces se ignorará la última ubicación. – Dharmendra

4

Usaría un servicio de intención y simplemente usaría el AlarmManager para disparar intenciones.

La principal ventaja de esto es que no existe un código de rosca que preocuparse, ya que hace su trabajo en el fondo

ACTUALIZACIÓN

Otro enfoque interesante se puede encontrar en https://stackoverflow.com/a/7709140/808940

+0

Y ¿qué pasa con la llamada onLocationChanged? ¿Tiene su propio hilo o fuego un IntentService también? También necesito saber si la llamada a la web fue exitosa o no. Esta parte no creo que sea fácil de hacer con un IntentService. Creo que debería haber una transmisión enviada, ¿verdad? – Alin

2
  • el servicio se ejecuta el mismo proceso que la aplicación principal, no hilo. Además, si desea ejecutar el servicio en otro proceso, puede usar la etiqueta android:process.

  • No estoy seguro de por qué quiere llamar a WebService cada 60 segundos, porque 60 segundos es demasiado menos. También debe omitir las llamadas al servicio web cuando la ubicación no ha cambiado, ya que requiere una comunicación de red y es una operación costosa.

  • No es necesario utilizar los ejecutores. Debe mantener la cantidad de hilos lo menos posible. Para realizar una tarea a un intervalo determinado, use AlarmManager para entregar el intento en un momento determinado. Verifique el método setRepeating() para configurar la alarma.

  • Otra cosa es, debe intentar evitar hacer cualquier tarea en Listener. Porque hay un timeout de 10 segundos que el sistema permite antes de considerar que el receptor/oyente debe bloquearse y un candidato debe ser asesinado. Debe usar Handler para realizar tareas en el hilo de fondo (es decir, cada vez que reciba la actualización del oyente, agregue un mensaje a la cola del controlador y se seleccionará cuando el hilo del controlador sea gratuito).

-1

Debe utilizar AsynchTask:

public class RefreshTask extends AsyncTask<Integer, Void, Integer> { 



    /** 
    * The system calls this to perform work in a worker thread and delivers 
    * it the parameters given to AsyncTask.execute() 
    */ 

    public RefreshTask() { 

    } 

    protected Integer doInBackground(Integer... millis) { 
     try{ 
      int waitTime = 0; 
      while(waitTime<60000){ 
       Thread.sleep(100); 
       waitTime += 100; 
      } 

      //update location here 

     }catch(InterruptedException e){ 

     } 



     return 1; 
    } 

    /** 
    * The system calls this to perform work in the UI thread and delivers 
    * the result from doInBackground() 
    */ 
    protected void onPostExecute(Integer result) { 
     new RefreshTask.execute(); 
    } 


} 
+0

No use 'AsyncTask' para este tipo de problema. Dependiendo de la versión de la API, esto bloqueará el resto de las AsyncTasks. – chrulri

Cuestiones relacionadas