2011-07-28 6 views
5

En mi código estoy usando un IntentService para escuchar actualizaciones de ubicación (ya sea GPS o actualizaciones de red) y este IntentService se activa cuando se recibe un evento, por lo que se inicia con startService() desde cualquier actividad.IntentService: ¿Cómo poner en cola correctamente?

public class AddLocationService extends IntentService implements LocationListener { 
    /*My code here*/ 
} 

    @Override 
protected void onHandleIntent(Intent intent) { 
    if(getOldLoc() == null) 
    { 
     //Get a new location 
     this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TIME_INTERVAL_GPS, 0, this); 
     this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_INTERVAL_GPS, 0, this); 
     Log.d(AddLocationService.TAG, "Network listener started"); 

     this.time_start_listening = System.currentTimeMillis(); 
     mTimerThread mTimerRunnable = new mTimerThread(); 
     this.timerThread = new Thread(mTimerRunnable); 
     this.timerThread.start(); 
    } 
    else  
     /*REUSE OLD LOCATION*/ 
} 

Ahora mi problema es: Cuando dos eventos comienzan este IntentService y la segunda comienza mientras el primero sigue solicitando para las actualizaciones, me gustaría que el segundo que esperar hasta primera es totalmente terminado (localización encontró O termina el hilo del temporizador). Sin embargo, cada vez que se ejecuta IntentService por segunda vez (la primera instancia aún se está ejecutando), me imprime el registro y lo hace como se estaba ejecutando en paralelo.

Sin embargo pensé que el objetivo principal de IntentService es que es algo secuencial por lo que un segundo intento tendría que esperar hasta el primero de ellos se hace ...

¿He Missunderstood algo?

Respuesta

3

Parece que su método onHandleIntent no está bloqueando el hilo en el que se está ejecutando, por lo que volverá rápidamente y permitirá que el segundo intento sea procesado. No solo eso, sino que es poco probable que se procesen las devoluciones de llamada desde el LocationManager a ese hilo, ya que es probable que el hilo de fondo se mate cuando onHandleIntent finaliza.

Si realmente desea utilizar IntentService para administrar su cola de intención, deberá realizar su gestión de ubicación en su propio hilo y unir el hilo de IntentService al subproceso de ubicación mientras está esperando la devolución de llamada de la ubicación.

Heres un poco de código que demuestra la idea:

public class TestService extends IntentService { 
    private static final String TAG = "TestService"; 

    private Location mLocation = null; 

    public TestService() { 
     super(TAG); 
    } 

    @Override 
    public void onHandleIntent(Intent intent) { 
     Log.d(TAG, "onHandleIntent"); 

     if (mLocation == null) { 
      Log.d(TAG, "launching location thread"); 
      LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); 

      LocationThread thread = new LocationThread(locationManager); 
      thread.start(); 
      try { 
       thread.join(10000); 
      } catch (InterruptedException e) { 
       Log.d(TAG, "timeout"); 
       return; 
      } 

      Log.d(TAG, "join finished, loc="+mLocation.toString()); 
     } else { 
      Log.d(TAG, "using existing loc="+mLocation.toString()); 
     } 
    } 

    private class LocationThread extends Thread implements LocationListener { 
     private LocationManager locationManager = null; 

     public LocationThread(LocationManager locationManager) { 
      super("UploaderService-Uploader"); 
      this.locationManager = locationManager; 
     } 

     @Override 
     public void run() { 
      Log.d(TAG, "Thread.run"); 
      Looper.prepare(); 
      this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); 
      this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); 

      Looper.loop(); 
     } 

     @Override 
     public void onLocationChanged(Location location) { 
      // TODO Auto-generated method stub 
      Log.d(TAG, "onLocationChanged("+location.toString()+")"); 
      mLocation = location; 
      Looper.myLooper().quit(); 
     } 

     @Override 
     public void onProviderDisabled(String arg0) { 
     } 

     @Override 
     public void onProviderEnabled(String arg0) { 
     } 

     @Override 
     public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 
     } 

    } 
} 

De interés en el Looper hay que ejecuta un bucle de mensajes en el hilo (para permitir el manejo de las devoluciones de llamada).

Dado el esfuerzo requerido para hacer esto con IntentService, podría valer la pena investigar derivando del Servicio y gestionando su propia cola de intención.

+0

Hola @Rob, Gracias por responder. ¿Podría ser más específico cuando dice que el método 'onHandleIntent' no está bloqueando el hilo? ¿Qué debo hacer para bloquearlo? ¿Tiene algo que ver con Flags al crear la intención de otra actividad o es algo que debería hacer en el método 'onHandleIntent()'? – Pom12

+0

EDIT: Creo que entiendo lo que quiere decir: mi IntentService regresa mientras sigue solicitando actualizaciones. ¿Cómo puedo mantenerlo bloqueado? ¿El dúo 'wait() - notify()' sería una buena idea? – Pom12

+0

Tipo de, he actualizado mi respuesta con más información sobre cómo solucionarlo – Rob

2

onHandleIntent ya está en su propio hilo. Usted no (no debería) crear allí. Todo es manejado por IntentService por usted.

1

Gracias a un millón, eso es exactamente lo que necesitaba para manejar las solicitudes de ubicación. Gracias por las explicaciones y por dejarme en claro, no estaba muy familiarizado con todo el concepto de looper, ¡ahora lo entiendo mejor!

En caso de que alguien necesita el mismo tipo de cosas, no se olvide de detener el hilo del áncora si su hilo de ubicación no se detiene de forma natural (fin del tiempo de join(millis)), mediante la adición de esto en onHandleIntent():

   if(thread.isAlive()) 
       { 
        thread.onThreadStop(); 
        try{ 
         thread.interrupt(); 
        }catch (Exception e) { 
         Log.d(TAG, "Exception on interrupt: " + e.getMessage()); 
        } 
       } 

después de thread.join(yourTime), por ejemplo, si no encontró ninguna actualización de ubicación, aún detiene el hilo después de un tiempo determinado. Y en el método onThreadStop():

   /*We remove location updates here and stop the looper*/ 
       public void onThreadStop() 
       { 
        this.locationManager1.removeUpdates(this); 
        handleLocationChange(AddLocationService.this.currentBestLocation); 
        Looper.myLooper().quit(); 
       } 

Sin embargo me pareció ver a mis dos intentos de ser tratados de la primera vez que me encontré con este código, pero ahora sólo la primera es tratada cuando tengo varios intentos sin dejar de solicitar actualizaciones de ubicación. Mi método onHandleIntent() parece ejecutarse correctamente, detiene el hilo después del tiempo especificado e incluso muestra el último Log (última instrucción del método) pero el segundo intento no se ejecuta ... ¿Tiene alguna idea de por qué?

+0

Después de algunas pruebas noté que en algunos casos solamente (cuando llamo a 'thread.interrupt()', es decir, cuando expiró el tiempo) el hilo aún se está ejecutando al final, y es probable que por eso no se trate el siguiente intento. Sin embargo, cuando el hilo termina normalmente, el hilo se detiene por completo ('thread.isAlive()' devuelve false) y se envían mis próximos intentos. Así que mi pregunta será: ¿cómo detener correctamente mi hilo, y/o por qué no se detiene cuando se utiliza 'thread.interrupt()' ?? – Pom12

Cuestiones relacionadas