终于明白了Handler怎么线程间通信的

4,189 阅读4分钟

一直对handler似懂非懂,这次看了别的文章加上自己的理解,终于明白Handler到底是如何实现线程间的通信了.大家共同探讨研究.
首先得明白,一个线程只有一个Looper和MessageQueue.调用本线程的Handler只能发送Message到本线程的MessageQueue.那怎么区分Handler是哪个线程的呢,是通过Handler对象中的Looper对象.然后本线程Looper对象loop(),不断从MessageQueue取消息.

1.主线程初始化Handler

//内存泄漏的问题请先忽略
 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
            ...
            }
        }
    };

直接新建一个Handler,它是主线程的.答案在源码.看下面.

//Handler源码片段
if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
   ...

        mLooper = Looper.myLooper(); //注意这句
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
    ...

mLooper = Looper.myLooper(); 这句代码获取的是主线程的Looper,而它在ActivityThread中已经初始化过了,这里不多说.

2.子线程发消息给主线程

a.在子线程里发送消息

private void childThreadSendMessageToMain() {
        new Thread(){
            @Override
            public void run() {
                super.run();
                Message message = handler.obtainMessage();
                message.what = mess_thread1;
                message.obj = "我是子线程1发来的消息";
                handler.sendMessage(message); //注意这句
            }
        }.start();

    }

handler.sendMessage(message); 这里的handler是我们上面在主线程初始化的,是主线程的Handler,这样在主线程的handleMessage()中就可以收到子线程发来的Message

b.在主线程接收消息

public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                //注意这里
                case mess_thread1:
                    Log.d(TAG, "handleMessage: 接收到来自mess_thread1的消息");
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                ...
            }
        }

c.结果打印

D/ScrollingActivity: handleMessage: 接收到来自mess_thread1的消息
D/ScrollingActivity: handleMessage: msg.obj=我是子线程1发来的消息

2.主线程发消息给子线程

这里有个问题,当我在主线程使用子线程Handler时,子线程的Handler没有初始化好怎么办?我们这样解决:
首先: 子线程里初始化Handler
再次: 子线程发送给主线程消息: 子线程的Handler准备好了
再次: 主线程使用子线程的Handler发送消息
最后: 子线程接收并处理主线程发送过来的消息

a.我们改变写法,在主线程写一个类继承自Handler

private class ChildHandler extends Handler{
        //参数为looper,到时候传入一个子线程的looper,这个handler就成了子线程的了
        private ChildHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
            ...
            }
        }
    }

b.开始在子线程new Handler,并且发送消息

private void initChildHandler(){
        new Thread(){
            @Override
            public void run() {
                Looper.prepare();
                childThreadHandler = new ChildHandler(Looper.myLooper());
                Message message = handler.obtainMessage();
                message.what = child_handler_ok;
                message.obj = "子线程handler准备好了";
                handler.sendMessage(message);
                Looper.loop();

            }
        }.start();
    }

c.主线程接收"子线程handler准备好"的消息,并使用子线程的Handler给子线程发消息

//接收处理子线程handler准备好的消息
private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case child_handler_ok:
                    Log.d(TAG, "handleMessage: 接收到子线程消息");
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                    sendMessageToChildThread();
                    break;
            }
        }
    };
    
    

d.sendMessageToChildThread方法的具体实现

    //使用子线程handler发送消息到子线程
    private void sendMessageToChildThread() {
        Message message = childThreadHandler.obtainMessage();
        message.what = mess_mainThread;
        message.obj = "我是主线程,已收到子线程handler准备好的消息";
        childThreadHandler.sendMessage(message);
    }

e.子线程接收主线程发来的消息

private class ChildHandler extends Handler{
        private ChildHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case mess_mainThread:
                    Log.d(TAG, "handleMessage: mess_mainThread");
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                    ...
                    break;
                ...
            }
        }
    }

f.结果打印

handleMessage: child_handler_ok
handleMessage: msg.obj=子线程handler准备好了
handleMessage: mess_mainThread
handleMessage: msg.obj=我是主线程,已收到子线程handler准备好的消息

3.子线程发消息给子线程

a.接着上面,我们再新建一个线程,称之为子线程2,原来的子线程称之为子线程1,

//在子线程2中使用子线程1的handler发送消息,实现了子线程之间的通信
  private void initChild2Thread() {
        new Thread(){
            @Override
            public void run() {
                Message message = childThreadHandler.obtainMessage();
                message.what = child2_thread;
                message.obj = "我是另一个子线程发送的消息";
                childThreadHandler.sendMessage(message);
            }
        }.start();
    }

b.我们在子线程1中接收

//这里说明一下,由于new的时候我们传入了子线程1的looper,所以这个handler属于子线程1
private class ChildHandler extends Handler{
        private ChildHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                ...
                case child2_thread:
                    Log.d(TAG, "handleMessage: child2_thread" );
                    Log.d(TAG, "handleMessage: msg.obj=" + msg.obj);
                    break;
            }
        }
    }

c.结果打印

D/ScrollingActivity: handleMessage: child2_thread
D/ScrollingActivity: handleMessage: msg.obj=我是另一个子线程发送的消息

4.总结

想给哪个线程发消息,就使用目标线程的Handler对象调用sendMessage(message).
而区别Handler是哪个线程的,就是Handler持有哪个线程的Looper.