Ejecutando el código en el hilo principal desde otro hilo

En un servicio de Android, he creado hilo (s) para hacer alguna tarea en segundo plano.

Tengo una situación en la que el hilo necesita publicar determinada tarea en la cola de mensajes del hilo principal, por ejemplo, Runnable .

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

Gracias,

NOTA: Esta respuesta ha recibido tanta atención, que 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í hay 2 soluciones posibles:

1. Si su hilo de fondo tiene una referencia a un objeto Context :

Asegúrese de que sus subprocesos de trabajo en segundo plano tengan acceso a un objeto de Contexto (puede ser el contexto de la Aplicación o el contexto del Servicio). Entonces haz esto en el hilo 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 su hilo de fondo no tiene (o no necesita) un objeto Context

(sugerido 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); 

Como comentaba a continuación, señaló 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 complicado tema de la comunicación de la actividad de servicio, lea toda la sección de Servicios del documento oficial; es complejo, por lo que sería rentable comprender los conceptos básicos: http://developer.android.com/guide/components/services.html #Notificaciones

El siguiente método puede funcionar en casos más simples.

Si te entiendo correctamente, necesitas que se ejecute algún código en el hilo de la GUI de la aplicación (no puedo pensar en nada más llamado hilo “principal”). Para esto hay un método en la 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

Espero que esto es lo que estás buscando.

Hay otra manera simple, si no tienes acceso al Contexto.

1). Crea un controlador desde el looper principal:

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

2). Implementar una interfaz Runnable:

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

3). Publica tu Runnable en uiHandler:

 uiHandler.post(runnable); 

Eso es todo 😉 Diviértete con los hilos, pero no te olvides de sincronizarlos.

Si ejecuta código en un hilo, por ejemplo, demorando alguna acción, entonces necesita invocar runOnUiThread desde el contexto. Por ejemplo, si su código está dentro de la clase MainActivity , use esto:

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

Si su método puede ser invocado desde el hilo principal (UI) o desde otros hilos, necesita una verificación como:

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

Un bloque de código condensado es el 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.

Equivalente de Kotlin:

  Handler(Looper.getMainLooper()).post(Runnable { // things to do on the main thread }) 

Un método en el que puedo pensar es esto:

1) Deje que la interfaz de usuario se una al servicio.
2) Exponga un método como el que se muestra a continuación mediante el Binder que registra su Handler :

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

3) En el hilo de UI, llame al método anterior después de vincularlo al servicio:

 mBinder.registerHandler(new Handler()); 

4) Use el controlador en el hilo del Servicio para publicar su tarea:

 mHandler.post(runnable); 

HandlerThread es la mejor opción para los hilos normales de Java en Android.

  1. Crea un HandlerThread y comienza
  2. Crear un controlador con Looper desde HandlerThread: requestHandler
  3. post una tarea requestHandler en requestHandler

Comunicación con UI Thread de HandlerThread

  1. Cree un Handler con Looper para el hilo principal: responseHandler y anule el método handleMessage
  2. Dentro de la tarea Runnable de otro Thread ( HandlerThread en este caso), sendMessage en responseHandler
  3. Esta sendMessage resultado sendMessage de handleMessage en responseHandler .
  4. Obtener atributos del Message y procesarlo, actualizar la interfaz de usuario

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

Código de muestra:

 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-be-be-usand-them-in-your-android-apps

android-looper-handler-handlerthread-i

Sigue 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

crear un controlador en el oncreate

  handler = new Handler(); 

luego úsalo así

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

Sé que esta es una vieja pregunta, pero me encontré con un hilo principal de una sola línea que uso tanto en Kotlin como en Java. Puede que esta no sea la mejor solución para un servicio, pero para llamar a algo que cambie la UI dentro de un fragmento, esto es extremadamente simple y obvio.

Java (8):

  getActivity().runOnUiThread(()->{ //your main thread code }); 

Kotlin:

 this.runOnUiThread(()->{ //your main thread code }); 
 public void mainWork() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { //Add Your Code Here } }); } 

Esto también puede funcionar en una clase de servicio sin problemas.