我有一个工作线程,它在后台处理消息。如下所示:
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
会将自己与错误的线程相关联。
这似乎不是一种罕见的情况。我可以想出几个变通方法,它们都很难看:
类工作者扩展线程{公共易失性处理程序;//实际上是私有的,当然是公共的void run() { Looper.prepare();mHandler = new处理程序(){ //处理程序挂接到当前线程的公共布尔值handleMessage(消息消息){ // ... } };notifyAll();// <-添加的Looper.loop();}}
在主线程中:
Worker =新的Worker();worker.start();worker.wait();// <-添加的worker.handler.sendMessage(...);
但这也是不可靠的:如果notifyAll()
发生在wait()
之前,那么我们永远不会被唤醒!
Message
传递给Worker
的构造函数,让run()
方法发布它。一个特别的解决方案不适用于多个消息,或者如果我们不想立即发送它,但很快就会after.
handler
字段不再是null
。是的,这是最后的手段...<代码>H219<代码>G220我想代表Worker
线程创建一个Handler
和MessageQueue
,但这似乎是不可能的。最优雅的解决方法是什么?
发布于 2011-02-01 04:35:21
最终的解决方案(不包括错误检查),这要归功于CommonsWare:
class Worker extends HandlerThread {
// ...
public synchronized void waitUntilReady() {
d_handler = new Handler(getLooper(), d_messageHandler);
}
}
在主线程中:
Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);
这要归功于HandlerThread.getLooper()
的语义,它会一直阻塞,直到循环程序初始化。
顺便说一句,这类似于我上面的解决方案#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;
}
关键的区别在于,它不检查工作线程是否正在运行,而是检查它是否实际创建了一个循环;要做到这一点,方法是将该循环存储在私有字段中。好的!
发布于 2015-08-16 06:58:29
看一看HandlerThread
的源代码
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
基本上,如果你在worker中扩展Thread并实现自己的循环,那么你的主线程类应该扩展worker并在那里设置你的处理程序。
发布于 2015-11-24 21:59:15
这是我的解决方案: MainActivity:
//Other Code
mCountDownLatch = new CountDownLatch(1);
mainApp = this;
WorkerThread workerThread = new WorkerThread(mCountDownLatch);
workerThread.start();
try {
mCountDownLatch.await();
Log.i("MsgToWorkerThread", "Worker Thread is up and running. We can send message to it now...");
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(this, "Trial run...", Toast.LENGTH_LONG).show();
Message msg = workerThread.workerThreadHandler.obtainMessage();
workerThread.workerThreadHandler.sendMessage(msg);
WorkerThread类:
public class WorkerThread extends Thread{
public Handler workerThreadHandler;
CountDownLatch mLatch;
public WorkerThread(CountDownLatch latch){
mLatch = latch;
}
public void run() {
Looper.prepare();
workerThreadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i("MsgToWorkerThread", "Message received from UI thread...");
MainActivity.getMainApp().runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.getMainApp().getApplicationContext(), "Message received in worker thread from UI thread", Toast.LENGTH_LONG).show();
//Log.i("MsgToWorkerThread", "Message received from UI thread...");
}
});
}
};
Log.i("MsgToWorkerThread", "Worker thread ready...");
mLatch.countDown();
Looper.loop();
}
}
https://stackoverflow.com/questions/4838207
复制相似问题