【发布时间】:2011-06-17 19:34:24
【问题描述】:
我有一个位于后台处理消息的工作线程。像这样的:
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();
}
}
从主线程(UI线程,没关系)我想做这样的事情:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
问题在于,这为我设置了一个漂亮的竞争条件:在读取 worker.handler 时,无法确定工作线程已经分配给该字段!
我不能简单地从Worker的构造函数中创建Handler,因为构造函数在主线程上运行,所以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。是的,最后的手段……
我想代表Worker 线程创建Handler 和MessageQueue,但这似乎是不可能的。最优雅的方法是什么?
【问题讨论】:
-
您没有使用
HandlerThread的任何特殊原因? -
@CommonsWare:嗯,不知道它的存在。文档中没有交叉引用。它的
getLooper()方法阻塞,直到我们有一个Looper,然后我们可以使用new Handler(worker.getLooper())从主线程 来初始化Handler。这样就可以解决问题了,对吧? -
我想是的。 OTOH,我自己用的不多,所以我可能会遗漏一些东西。
-
@CommonsWare:它解决了这个问题。现在,如果您将其作为答案发布,我将在其旁边放一个大的绿色复选标记;)
-
实际上,我认为如果您自己回答会更好,解释一下
HandlerThread如何适合您的Worker模式。至少,你会比我解释得更好,因为这是你的问题和解决方案的实现——我只是指出了一个帮助类来解决这个问题。
标签: android multithreading handler looper