У меня есть рабочий поток, который сидит в фоновом режиме, обрабатывая сообщения. Что-то вроде этого:
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();
}
}
Из основного потока (поток пользовательского интерфейса, не важно) Я хотел бы сделать что-то вроде этого:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
Проблема заключается в том, что это меня подводит к прекрасному состоянию гонки: во время чтения worker.handler
нет способа убедиться, что рабочий поток уже назначен этому полю!
Я не могу просто создать Handler
из конструктора Worker
, потому что конструктор работает в основном потоке, поэтому Handler
свяжется с неправильным потоком.
Это вряд ли кажется необычным сценарием. Я могу придумать несколько обходных решений, все они уродливые:
-
Что-то вроде этого:
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(); } }
И из основного потока:
Worker worker = new Worker(); worker.start(); worker.wait(); // <- ADDED worker.handler.sendMessage(...);
Но это также не является надежным: если
notifyAll()
происходит доwait()
, мы никогда не будем разбужены! -
Передача начального конструктора
Message
в конструкторWorker
, содержащий методrun()
. Специальное решение не будет работать для нескольких сообщений, или если мы не хотим отправлять его сразу же, но вскоре. -
Ожидание в ожидании до тех пор, пока поле
Handler
больше не будетnull
. Да, последнее средство...
Я хотел бы создать Handler
и MessageQueue
от имени потока Worker
, но это не представляется возможным. Каков самый изящный выход из этого?