Tengo un hilo de trabajo que se encuentra en segundo plano, procesando mensajes. Algo como esto:
class Worker extends Thread {
public volatile Handler handler; // actually private, of course
public void run() {
Looper.prepare();
mHandler = new Handler() { // the Handler hooks up to the current Thread
public boolean handleMessage(Message msg) {
// ...
}
};
Looper.loop();
}
}
Desde el hilo principal (hilo de la interfaz de usuario, no es que importe) me gustaría hacer algo como esto:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
El problema es que esto me prepara para una hermosa condición de carrera: en el momento en que worker.handlerse lee, ¡no hay forma de estar seguro de que el hilo de trabajo ya se haya asignado a este campo!
No puedo simplemente crear el Handlerdesde el Workerconstructor de, porque el constructor se ejecuta en el hilo principal, por lo que Handlerse asociará con el hilo incorrecto.
Esto no parece un escenario poco común. Puedo encontrar varias soluciones, todas feas:
Algo como esto:
class Worker extends Thread { public volatile Handler handler; // actually private, of course public void run() { Looper.prepare(); mHandler = new Handler() { // the Handler hooks up to the current Thread public boolean handleMessage(Message msg) { // ... } }; notifyAll(); // <- ADDED Looper.loop(); } }Y del hilo principal:
Worker worker = new Worker(); worker.start(); worker.wait(); // <- ADDED worker.handler.sendMessage(...);Pero esto tampoco es confiable: si
notifyAll()sucede antes delwait(), ¡nunca nos despertaremos!Pasando una inicial
MessagealWorkerconstructor de, haciendo que elrun()método la publique. Una solución ad-hoc, no funcionará para varios mensajes, o si no queremos enviarla de inmediato, pero poco después.Ocupado esperando hasta que el
handlercampo ya no esténull. Sí, un último recurso ...
Me gustaría crear un Handlery MessageQueueen nombre del Workerhilo, pero esto no parece ser posible. ¿Cuál es la forma más elegante de salir de esto?
HandlerThread?