首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何创建一个Looper线程,然后立即向其发送消息?

如何创建一个Looper线程,然后立即向其发送消息?
EN

Stack Overflow用户
提问于 2011-01-30 01:13:31
回答 4查看 45.5K关注 0票数 77

我有一个工作线程,它在后台处理消息。如下所示:

代码语言:javascript
复制
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线程,并不重要)中,我想这样做:

代码语言:javascript
复制
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);

麻烦的是,这为我设置了一个漂亮的竞态条件:在读取worker.handler时,无法确定工作线程是否已经分配给这个字段!

我不能简单地从Worker的构造函数创建Handler,因为构造函数在主线程上运行,所以Handler会将自己与错误的线程相关联。

这似乎不是一种罕见的情况。我可以想出几个变通方法,它们都很难看:

  1. 类似于:

类工作者扩展线程{公共易失性处理程序;//实际上是私有的,当然是公共的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.

  • Busy-waiting,直到handler字段不再是null。是的,这是最后的手段...<代码>H219<代码>G220

我想代表Worker线程创建一个HandlerMessageQueue,但这似乎是不可能的。最优雅的解决方法是什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-02-01 04:35:21

最终的解决方案(不包括错误检查),这要归功于CommonsWare:

代码语言:javascript
复制
class Worker extends HandlerThread {

    // ...

    public synchronized void waitUntilReady() {
        d_handler = new Handler(getLooper(), d_messageHandler);
    }

}

在主线程中:

代码语言:javascript
复制
Worker worker = new Worker();
worker.start();
worker.waitUntilReady(); // <- ADDED
worker.handler.sendMessage(...);

这要归功于HandlerThread.getLooper()的语义,它会一直阻塞,直到循环程序初始化。

顺便说一句,这类似于我上面的解决方案#1,因为HandlerThread的实现大致如下(我喜欢开源):

代码语言:javascript
复制
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;
}

关键的区别在于,它不检查工作线程是否正在运行,而是检查它是否实际创建了一个循环;要做到这一点,方法是将该循环存储在私有字段中。好的!

票数 64
EN

Stack Overflow用户

发布于 2015-08-16 06:58:29

看一看HandlerThread的源代码

代码语言:javascript
复制
@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并在那里设置你的处理程序。

票数 1
EN

Stack Overflow用户

发布于 2015-11-24 21:59:15

这是我的解决方案: MainActivity:

代码语言:javascript
复制
//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类:

代码语言:javascript
复制
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();
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4838207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档