Android 如何创建一个活套线程,然后立即向其发送消息?
我有一个工作线程,它位于后台,处理消息。大概是这样的:Android 如何创建一个活套线程,然后立即向其发送消息?,android,multithreading,handler,looper,Android,Multithreading,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 curren
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(...);
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();
}
}
从主线程(UI线程,不重要)开始,我想做如下事情:
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(...);
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.handler
时,无法确保worker线程已经分配给该字段
我不能简单地从工作者
的构造函数创建处理程序
,因为构造函数在主线程上运行,因此处理程序
将自身与错误的线程关联
这似乎并不罕见。我可以想出几个解决办法,都很难看:
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(...);
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();
}
}
类工作线程扩展{
public volatile Handler;//当然,实际上是私有的
公开募捐{
Looper.prepare();
mHandler=new Handler(){//处理程序连接到当前线程
公共布尔句柄消息(消息消息消息){
// ...
}
};
notifyAll();//最终解决方案(减去错误检查),多亏了Commonware:
class Worker extends HandlerThread {
// ...
public synchronized void waitUntilReady() {
d_handler = new Handler(getLooper(), d_messageHandler);
}
}
从主线来看:
Worker worker = new Worker();
worker.start();
worker.wait(); // <- ADDED
worker.handler.sendMessage(...);
Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);
关键区别在于,它不检查工作线程是否正在运行,而是检查它是否实际创建了一个循环器;这样做的方法是将循环器存储在一个私有字段中。很好!类WorkerThread Extendes thread{
class WorkerThread extends Thread {
private Exchanger<Void> mStartExchanger = new Exchanger<Void>();
private Handler mHandler;
public Handler getHandler() {
return mHandler;
}
@Override
public void run() {
Looper.prepare();
mHandler = new Handler();
try {
mStartExchanger.exchange(null);
} catch (InterruptedException e) {
e.printStackTrace();
}
Looper.loop();
}
@Override
public synchronized void start() {
super.start();
try {
mStartExchanger.exchange(null);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
专用交换机mStartExchanger=新交换机();
私人经理人;
公共处理程序getHandler(){
返回mHandler;
}
@凌驾
公开募捐{
Looper.prepare();
mHandler=新处理程序();
试一试{
mStartExchanger.exchange(空);
}捕捉(中断异常e){
e、 printStackTrace();
}
loop.loop();
}
@凌驾
公共同步的void start(){
super.start();
试一试{
mStartExchanger.exchange(空);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
查看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中扩展线程并实现自己的循环器,那么您的主线程类应该扩展worker并在那里设置处理程序。这是我的解决方案:
主要活动:
//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();
}
}
您没有使用HandlerThread
的任何特定原因?@commonware:Hmm,不知道它存在。文档中没有交叉引用。它的getLooper()
方法会阻塞,直到我们有了Looper
,然后我们才能使用新处理程序(worker.getLooper())
从主线程初始化处理程序
。这会解决问题,对吗?我想是的。OTOH,我自己不太使用它,所以我可能遗漏了一些东西。@Commonware:它解决了问题。现在如果你把它作为一个答案,我会在它旁边打一个绿色的大复选标记;)事实上,我认为如果你自己回答了它,解释了HandlerThread
如何适应你的Worker
模式。至少,你会比我解释得更好,因为这是你的问题和你的解决方案实现——我刚刚指出了一个帮助类来解决这个问题。谢谢你。我的评论只是为了指出tUntilReady()必须在worker.start()之后调用。回头看,这听起来很明显,但我花了一点时间才弄明白我在获取空指针异常时出错的地方。@Snicolas你不能,因为处理程序被绑定到创建它的线程上。在HandlerThread的构造函数中初始化它将导致在主线程或创建HandlerThread的任何位置生成处理程序d、 如果要使用处理程序构造函数,并将处理程序的循环器作为参数(waituntilready中使用的循环器)我很确定这会导致死锁。好的,这是一个很好的观点。Thx用于发布。因此,为了保护处理程序不被误用,您可以将处理程序方法包装到HandlerThread中,该线程可以充当facade,并在检查处理程序初始化后将每个调用委托给处理程序。这将是封装处理程序和预处理的更好方法不要忘记等待。@Thomasd_处理程序
的主要用途是什么?d_messageHandler
处理消息,对吗?但是您正在使用work.handler
发送meesage这很有趣,但是如果您提供一些关于d_处理程序和d_messageHandler的注释,它会更有用e、 以及如何使用它们。