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,并在检查处理程序初始化后将每个调用委托给处理程序。这将是封装处理程序和预处理的更好方法不要忘记等待。@Thomas
    d_处理程序
    的主要用途是什么?
    d_messageHandler
    处理消息,对吗?但是您正在使用
    work.handler
    发送meesage这很有趣,但是如果您提供一些关于d_处理程序和d_messageHandler的注释,它会更有用e、 以及如何使用它们。