2012-06-20 20 views
221

En un servicio de Android he creado hebras para realizar alguna tarea en segundo plano.Código de ejecución en el hilo principal de otro hilo

Tengo una situación donde el hilo necesita para publicar cierta tarea en la cola de mensajes del hilo principal, por ejemplo, un Runnable.

¿Hay alguna manera de obtener Handler del hilo principal y publicar Message/Runnable desde el otro hilo?

Gracias,

+2

También puede utilizar el receptor de difusión personalizada .... intentar mi respuesta aquí, [Receptor Broadcast Interior] [1] [1]: http://stackoverflow.com/a/22541324/1881527 –

+0

Hay muchas maneras. Además de la respuesta de David y el comentario de dzeikei en su respuesta, (3) puede usar un Receptor de radiodifusión, o (4) pasar el controlador en extras de Intención utilizada para iniciar el servicio y luego recuperar el manejador del subproceso principal dentro del servicio utilizando getIntent () .getExtras(). –

Respuesta

475

NOTA: Esta respuesta ha g A pesar de tanta atención, necesito actualizarla. Desde que se publicó la respuesta original, el comentario de @dzeikei recibió casi tanta atención como la respuesta original. Así que aquí están 2 soluciones posibles:

1. Si el subproceso de fondo tiene una referencia a un objeto Context:

asegurarse de que sus subprocesos de trabajo de fondo tienen acceso a un objeto de contexto (puede ser el contexto de aplicaciones o el contexto del Servicio). A continuación, sólo hacer esto en el subproceso de trabajo de fondo:

// Get a handler that can be used to post to the main thread 
Handler mainHandler = new Handler(context.getMainLooper()); 

Runnable myRunnable = new Runnable() { 
    @Override 
    public void run() {....} // This is your code 
}; 
mainHandler.post(myRunnable); 

2. Si el subproceso de fondo no tiene (o necesidad) de un objeto Context

(sugerida por @dzeikei):

// Get a handler that can be used to post to the main thread 
Handler mainHandler = new Handler(Looper.getMainLooper()); 

Runnable myRunnable = new Runnable() { 
    @Override 
    public void run() {....} // This is your code 
}; 
mainHandler.post(myRunnable); 
+0

Gracias David funcionó para mí, una cosa más si me pudieras ayudar, si extiendo Handler e impl handleMessage() ¿evitaría que el hilo principal maneje sus mensajes? eso es solo una pregunta fuera de curosity. – Ahmed

+2

No. Si subclasifica 'Handler' (o utiliza la interfaz 'Handler.Callback'), su método' handleMessage() 'SOLO se ejecutará para los mensajes que se hayan publicado con su controlador. El hilo principal es usar un manejador diferente para publicar/procesar mensajes para que no haya conflicto. –

+0

Gracias David, resolvió mi confusión :) – Ahmed

4

Uno de los métodos que se me ocurre es la siguiente:

1) Que la interfaz de usuario se unen al servicio.
2) exponer un método como el de abajo por el Binder que registra su Handler:

public void registerHandler(Handler handler) { 
    mHandler = handler; 
} 

3) En el hilo de interfaz de usuario, llame al método anterior después de la unión al servicio:

mBinder.registerHandler(new Handler()); 

4) Utilice el controlador de hilo del servicio para publicar su tarea:

mHandler.post(runnable); 
116

Como a continuación se señala correctamente, esta no es una solución general para los servicios, solo para los hilos lanzados desde su actividad (un servicio puede ser un hilo, pero no todos). Sobre el tema complicado de comunicación de servicio-actividad por favor lea la sección de Servicios totalidad del documento oficial - es complejo, por lo que tendría que pagar para entender los conceptos básicos: http://developer.android.com/guide/components/services.html#Notifications

El siguiente método puede funcionar en casos simpliest.

Si te entiendo correctamente necesitas que se ejecute algún código en el hilo de la interfaz gráfica de usuario de la aplicación (no puedo pensar en nada más llamado hilo "principal"). Para ello existe un método en Activity:

someActivity.runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      //Your code to run in GUI thread here 
     }//public void run() { 
}); 

Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Hope esto es lo que busca.

+13

OP dice que está ejecutando hilos en un 'Servicio'. No puede usar 'runOnUiThread()' en un 'Servicio'. Esta respuesta es engañosa y no aborda la pregunta formulada. –

24

Si ejecuta código en un hilo, p. retrasar alguna acción, entonces necesita invocar runOnUiThread desde el contexto. Por ejemplo, si su código está dentro MainActivity clase a continuación, utilizar esto:

MainActivity.this.runOnUiThread(new Runnable() { 
    @Override 
    public void run() { 
     myAction(); 
    } 
}); 

Si su método puede ser reclamada en forma de (hilo de interfaz de usuario) principal o desde otros hilos que necesita un cheque como:

public void myMethod() { 
    if(Looper.myLooper() == Looper.getMainLooper()) { 
     myAction(); 
    } 
    else { 

} 
+7

OP dice que está ejecutando hilos en un 'Servicio'. No puede usar 'runOnUiThread()' en un 'Servicio'. –

+0

@DavidWasser ¿Está documentado en alguna parte? El método docs no menciona nada al respecto. http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29 –

+0

@GregBrown Como has indicado por tu enlace a la documentación de 'Activity',' runOnUiThread () 'es un método de' Actividad'. No es un método de 'Servicio', por lo tanto, no puede usarlo. ¿Qué podría ser más claro que eso? –

27

Hay otra forma simple, si no tiene acceso al Contexto.

1). Crear un controlador desde el looper principal:

Handler uiHandler = new Handler(Looper.getMainLooper()); 

2). Implemente una interfaz Runnable:

Runnable runnable = new Runnable() { // your code here } 

3). Publique Ejecutable a la uiHandler:

uiHandler.post(runnable); 

Eso es todo ;-) Diviértete con hilos, pero no se olvide de sincronizarlos.

2

HandlerThread es una mejor opción que los hilos normales de Java en Android.

  1. Crear un HandlerThread y empezar a que
  2. Crear una Handler con Looper de HandlerThread: requestHandler
  3. post una tarea Runnable en requestHandler

comunicación con hilo de interfaz de usuario de HandlerThread

  1. Crear una Handler con Looper de hilo principal: responseHandler y anular handleMessage método
  2. Dentro Runnable tarea de otro hilo (HandlerThread en este caso), lo llaman en sendMessageresponseHandler
  3. Esta invocación sendMessage resultado de handleMessage en responseHandler.
  4. Obtiene los atributos de la Message y procesarla, actualizar la interfaz de usuario

Ejemplo: Actualización TextView con los datos recibidos de un servicio web. Dado que el servicio web debe invocarse en un subproceso que no sea UI, se creó HandlerThread para el funcionamiento de la red.Una vez que obtenga el contenido del servicio web, envíe un mensaje a su manejador de subproceso principal (subproceso de interfaz de usuario) y que Handler manejará el mensaje y actualizará la interfaz de usuario.

Código de ejemplo:

HandlerThread handlerThread = new HandlerThread("NetworkOperation"); 
handlerThread.start(); 
Handler requestHandler = new Handler(handlerThread.getLooper()); 

final Handler responseHandler = new Handler(Looper.getMainLooper()) { 
    @Override 
    public void handleMessage(Message msg) { 
     txtView.setText((String) msg.obj); 
    } 
}; 

Runnable myRunnable = new Runnable() { 
    @Override 
    public void run() { 
     try { 
      Log.d("Runnable", "Before IO call"); 
      URL page = new URL("http://www.your_web_site.com/fetchData.jsp"); 
      StringBuffer text = new StringBuffer(); 
      HttpURLConnection conn = (HttpURLConnection) page.openConnection(); 
      conn.connect(); 
      InputStreamReader in = new InputStreamReader((InputStream) conn.getContent()); 
      BufferedReader buff = new BufferedReader(in); 
      String line; 
      while ((line = buff.readLine()) != null) { 
       text.append(line + "\n"); 
      } 
      Log.d("Runnable", "After IO call:"+ text.toString()); 
      Message msg = new Message(); 
      msg.obj = text.toString(); 
      responseHandler.sendMessage(msg); 


     } catch (Exception err) { 
      err.printStackTrace(); 
     } 
    } 
}; 
requestHandler.post(myRunnable); 

Artículos útiles:

handlerthreads-and-why-you-should-be-using-them-in-your-android-apps

android-looper-handler-handlerthread-i

0

seguir este método. Utilizando de esta manera, simplemente puede actualizar la interfaz de usuario desde un hilo de fondo. runOnUiThread trabajo en el hilo principal (UI). Creo que este fragmento de código es menos complejo y fácil, especialmente para principiantes.

AsyncTask.execute(new Runnable() { 
      @Override 
      public void run() { 

      //code you want to run on the background 
      someCode(); 

      //the code you want to run on main thread 
MainActivity.this.runOnUiThread(new Runnable() { 

        public void run() { 

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/ 
         executeAfterOperation(); 

        } 
       }); 
      } 
     }); 

en el caso de un servicio de

crear un controlador en el OnCreate

handler = new Handler(); 

entonces utilizar de esta

private void runOnUiThread(Runnable runnable) { 
     handler.post(runnable); 
    } 
+0

Gracias por este fragmento de código, que podría proporcionar alguna ayuda limitada e inmediata. Una [explicación adecuada mejoraría en gran medida su valor a largo plazo] (// meta.stackexchange.com/q/114762/350567) al mostrar * por qué * esta es una buena solución al problema y lo haría más útil para el futuro lectores con otras preguntas similares. Por favor [edite] su respuesta para agregar alguna explicación, incluidas las suposiciones que ha hecho. – iBug

4

un bloque de código condensada es la siguiente:

new Handler(Looper.getMainLooper()).post(new Runnable() { 
     @Override 
     public void run() { 
      // things to do on the main thread 
     } 
    }); 

Esto no implica pasar la referencia de la actividad o la referencia de la aplicación.

Cuestiones relacionadas