android - thread - Ejecutando código en el hilo principal de otro hilo
thread android studio ejemplo (12)
Como un comentarista a continuación señaló correctamente, esta no es una solución general para servicios, solo para subprocesos iniciados desde su actividad (un servicio puede ser un subproceso de este tipo, pero no todos lo son). En el complicado tema de la comunicación de servicio-actividad, lea toda la sección de Servicios del documento oficial: es complejo, por lo que le convendría comprender los conceptos básicos: http://developer.android.com/guide/components/services.html#Notifications
El método a continuación puede funcionar en los casos más simples.
Si le comprendo correctamente, necesita que se ejecute algún código en el subproceso de la GUI de la aplicación (no se puede pensar en nada más que se llame subproceso "principal"). Para esto hay un método de Activity
:
someActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
//Your code to run in GUI thread here
}//public void run() {
});
Espero que esto sea lo que buscas.
En un servicio de Android, he creado subprocesos para realizar alguna tarea en segundo plano.
Tengo una situación en la que un subproceso necesita publicar cierta tarea en la cola de mensajes del subproceso principal, por ejemplo, un Runnable
.
¿Hay alguna manera de obtener un Handler
del hilo principal y publicar un Message
/ Runnable
en mi otro hilo?
Gracias,
Hay otra forma sencilla, si no tiene acceso al Contexto.
1). Crea un manejador desde el looper principal:
Handler uiHandler = new Handler(Looper.getMainLooper());
2). Implementar una interfaz Runnable:
Runnable runnable = new Runnable() { // your code here }
3). Publique su Runnable en el uiHandler:
uiHandler.post(runnable);
Eso es todo ;-) Diviértete con hilos, pero no olvides sincronizarlos.
La forma más sencilla, especialmente si no tiene un contexto, si está utilizando RxAndroid, puede hacerlo:
AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}
NOTA: Esta respuesta ha recibido tanta atención que necesito actualizarla. Desde que se publicó la respuesta original, el comentario de @dzeikei ha recibido 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 de 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 del trabajador 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 necesita) un objeto de 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);
Para Kotlin, puedes usar Anko Corountines :
actualizar
doAsync {
...
}
obsoleto
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}
Sé que esta es una pregunta antigua, pero encontré un hilo principal de una 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 cambiará la interfaz de usuario 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
});
Si ejecuta código en un hilo, por ejemplo, retrasando 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 invocarse desde el subproceso principal (UI) o desde otros subprocesos, necesita una comprobación como:
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
Sigue este método. Usando de esta manera, simplemente puede actualizar la interfaz de usuario desde un hilo de fondo. RunOnUiThread funciona en el hilo principal (UI). Creo que este fragmento de código es menos complejo y fácil, especialmente para los 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 manejador en el oncreate
handler = new Handler();
entonces úsalo así
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
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 actividad o la referencia de aplicación.
Equivalente Kotlin:
Handler(Looper.getMainLooper()).post(Runnable {
// things to do on the main thread
})
Un método que puedo pensar es el siguiente:
1) Deje que la UI se una al servicio.
2) Exponga un método como el que se encuentra abajo en el Binder
que registra su Handler
:
public void registerHandler(Handler handler) {
mHandler = handler;
}
3) En el subproceso de la interfaz de usuario, llame al método anterior después de vincular al servicio:
mBinder.registerHandler(new Handler());
4) Utilice el controlador en el hilo del Servicio para publicar su tarea:
mHandler.post(runnable);
HandlerThread
es una mejor opción para los HandlerThread
normales de Java en Android.
- Crear un HandlerThread e iniciarlo
- Cree un controlador con Looper desde HandlerThread:
requestHandler
-
post
una tarearequestHandler
enrequestHandler
Comunicación con el hilo de UI de HandlerThread
- Cree un
Handler
conLooper
para el hilo principal:responseHandler
y anule el métodohandleMessage
- Dentro de la tarea
Runnable
de otro hilo (HandlerThread
en este caso), llame asendMessage
enresponseHandler
- Esta invocación del resultado de
handleMessage
dehandleMessage
enresponseHandler
. - Obtenga los atributos del
Message
y procéselo, actualice la interfaz de usuario
Ejemplo : actualice TextView
con los datos recibidos de un servicio web. Dado que el servicio web debe invocarse en un hilo no UI, se creó HandlerThread
para la operación de red. Una vez que obtenga el contenido del servicio web, envíe un mensaje a su controlador de subproceso principal (Hilo de la interfaz de usuario) y ese Handler
manejará el mensaje y actualizará la interfaz de usuario.
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-should-be-using-them-in-your-android-apps
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.