【问题标题】:Example communicating with HandlerThread与 HandlerThread 通信的示例
【发布时间】:2014-09-25 11:44:51
【问题描述】:

我想从 GUI 线程设置一个 HandlerThread。一段时间后,当在 GUI 上单击按钮时,它会运行 callHello(),然后将消息发送到位于非 GUI 线程上的 HelloLogger 对象,该对象异步记录“Hello World”。我已经尝试了很多东西,有些无限期地阻塞,有些永远不会收到消息等等。下面的代码或多或少与我得到的一样接近,请有人修改它以使其工作?

public class HandlerThreadExample {

    private MyHandlerThread mMyHandlerThread;
    private Looper mLooper;
    private Handler mHandler;

    public HandlerThreadExample(){
        mMyHandlerThread = new MyHandlerThread();
        mMyHandlerThread.start();
        mLooper = mMyHandlerThread.getLooper();
    }
    public void callHello() {
        mHandler.sendEmptyMessage(1);
    }
    private class MyHandlerThread extends HandlerThread {
        private HelloLogger mHelloLogger;
        private Handler mHandler;
        public MyHandlerThread() {
            super("The MyHandlerThread thread", HandlerThread.NORM_PRIORITY);
        }
        public void run (){
            mHelloLogger = new HelloLogger();
            mHandler = new Handler(getLooper()){
                public void handleMessage(Message msg){
                    mHelloLogger.logHello();
                }
            };
            super.run();
        }
    }
    private class HelloLogger {
        public HelloLogger (){
        }
        public void logHello(){
            Log.d("HandlerThreadExample", "Hello World");
        }
    }
}

找到的最佳示例:

至少现在我可以关闭该死的标签

解决方案由 pskink 提供帮助

public class HandlerThreadExample2 {
    private static int MSG_START_HELLO = 0;
    private static int MSG_HELLO_COMPLETE = 1;
    private HandlerThread ht;
    private Handler mHtHandler;
    private Handler mUiHandler;
    private boolean helloReady = false;
    public HandlerThreadExample2(){
        ht = new HandlerThread("The new thread");
        ht.start();
        Log.d(App.TAG, "UI: handler thread started");
        mUiHandler = new Handler(){
            public void handleMessage(Message msg){
                if (msg.what == MSG_HELLO_COMPLETE){
                    Log.d(App.TAG, "UI Thread: received notification of sleep completed ");
                    helloReady = true;              }
            }
        };
        mHtHandler = new Handler(ht.getLooper()){
            public void handleMessage (Message msg){
                if (msg.what == MSG_START_HELLO){
                    Log.d(App.TAG, "handleMessage " + msg.what + " in " + Thread.currentThread() + " now sleeping");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.d(App.TAG, "Woke up, notifying UI thread...");
                    mUiHandler.sendEmptyMessage(MSG_HELLO_COMPLETE);
                }
            }
        };
    }
    public void sendLongHello(){
        if (helloReady){
            Log.d(App.TAG, "sending hello " + Thread.currentThread());      
            mHtHandler.sendEmptyMessage(MSG_START_HELLO);
            helloReady = false;
        } else {
            Log.e(App.TAG, "Cannot do hello yet - not ready");
        }
    }
}

【问题讨论】:

  • 认为您可以使用 github.com/greenrobot/EventBus 用 4 行代码做到这一点
  • 非常有趣,谢谢,下次再研究。 +1。但我认为我应该在跑步之前先走路
  • 没问题,但说实话,尽管我已经编写了很多 Android 代码,但我还是放弃了使用 Handlers 和 Messages。当它可以做得非常简单,可读和可维护的IMO时,不需要做复杂的事情:)
  • 上帝知道,我知道你来自哪里!!!!有人告诉我这将是一个赏金问题,哈哈
  • 1) 创建一个新的 HandlerThread,2) start() 它,3) 创建一个新的 Handler。使用 ht.getLooper() 作为 Looper 参数,4) 发送消息

标签: android multithreading android-handler android-handlerthread


【解决方案1】:

这是一个工作示例:

HandlerThread ht = new HandlerThread("MySuperAwesomeHandlerThread");
ht.start();
Handler h = new Handler(ht.getLooper()) {
    public void handleMessage(Message msg) {
        Log.d(TAG, "handleMessage " + msg.what + " in " + Thread.currentThread());
    };
};
for (int i = 0; i < 5; i++) {
    Log.d(TAG, "sending " + i + " in " + Thread.currentThread());
    h.sendEmptyMessageDelayed(i, 3000 + i * 1000);
}

更新

制作两个类字段:

Handler mHtHandler;
Handler mUiHandler;

试试这个:

HandlerThread ht = new HandlerThread("MySuperAwsomeHandlerThread");
ht.start();
Callback callback = new Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == 0) {
            Log.d(TAG, "got a meaasage in " + Thread.currentThread() + ", now sleeping... ");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "woke up, notifying ui thread...");
            mUiHandler.sendEmptyMessage(1);
        } else
        if (msg.what == 1) {
            Log.d(TAG, "got a notification in " + Thread.currentThread());
        }
        return false;
    }
};
mHtHandler = new Handler(ht.getLooper(), callback);
mUiHandler = new Handler(callback);
mHtHandler.sendEmptyMessageDelayed(0, 3000);

您当然可以摆脱Callback 接口并创建两个具有覆盖handleMessage 方法的处理程序...

【讨论】:

  • +1,谢谢。我已经编辑了我的问题,添加了一个尝试整合您的答案的示例。我仍然不知道 GUI 线程如何判断工作线程何时完成操作(显然没有阻塞)。我需要添加什么才能调用 helloComplete() ?我需要在某个地方制作/获取另一个处理程序吗?
  • @pskink 你能解释一下回调和循环器是如何并行运行的吗?它与某种形式的调度器有关吗?
  • @Chris 最好的学习方法是运行我的第二个 sn-p 代码
  • 您希望它如何工作? start() 是非阻塞的,因此下一行的 getLooper() 可能会返回 null。
  • @YaroslavMytkalyk 不,它不能,阅读 HandlerThread#getLooper 文档
【解决方案2】:

您看到的问题是因为您的外部类正在使用私有 mHandler 字段,您的 HandlerThread 也是如此。外部类的字段未初始化。您不需要内部 mHandler。外部类可以从你在调用 start() 后立即抓取的 looper 中创建一个处理程序。

【讨论】:

    猜你喜欢
    • 2016-12-19
    • 2017-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多