Tho*_*mas 73 multithreading android handler looper
我有一个工作线程,它位于后台,处理消息.像这样的东西:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
从主线程(UI线程,不重要)我想做这样的事情:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
Run Code Online (Sandbox Code Playgroud)
麻烦的是,这为我设定了一个漂亮的竞争条件:在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();
}
}
Run Code Online (Sandbox Code Playgroud)
并从主线程:
Worker worker = new Worker();
worker.start();
worker.wait(); // <- ADDED
worker.handler.sendMessage(...);
Run Code Online (Sandbox Code Playgroud)
但这也不可靠:如果notifyAll()发生在之前wait(),那么我们永远不会被唤醒!
将一个首字母传递Message给Worker构造函数,让run()方法发布它.一个临时解决方案,不适用于多条消息,或者如果我们不想立即发送,但很快就会发送.
忙着等待直到handler现场不再null.是的,万不得已......
我想创建一个Handler和MessageQueue代表的Worker线程,但是这似乎并不可能.什么是最优雅的方式?
Tho*_*mas 61
最终的解决方案(减去错误检查),感谢CommonsWare:
class Worker extends HandlerThread {
// ...
public synchronized void waitUntilReady() {
d_handler = new Handler(getLooper(), d_messageHandler);
}
}
Run Code Online (Sandbox Code Playgroud)
并从主线程:
Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);
Run Code Online (Sandbox Code Playgroud)
这要归功于HandlerThread.getLooper()在初始化looper之前块的语义.
顺便说一句,这与我上面的解决方案#1类似,因为HandlerThread它的实现大致如下(得到爱开源):
public void run() {
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
}
public Looper getLooper() {
synchronized (this) {
while (mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
Run Code Online (Sandbox Code Playgroud)
关键的区别在于它不会检查工作线程是否正在运行,而是它实际上已经创建了一个looper; 并且这样做的方法是将活套存放在私人领域.太好了!
| 归档时间: |
|
| 查看次数: |
42044 次 |
| 最近记录: |