Handler到底是怎么实现子线程的Message到主线程下被处理的?

Handler机制的作用真的是线程间通信吗?
Handler到底是怎么实现子线程的Message到主线程下被处理的?

郭霖大神的文章:Android异步消息处理机制完全解析,带你从源码的角度彻底理解,详细分析了从sendMessage()到handleMessage()的过程。

handler.sendMessage(msg);是在子线程的run()方法中执行的,也就是说当前的代码执行环境是子线程,而handleMessage()方法是运行在主线程的,那么,具体是怎么实现的?

反复看郭霖大神的文章,可以梳理出一个逻辑:

  • 在子线程中,产生msg,并获取主线程的Handler,发送msg。
new Thread(new Runnable() {
	@Override
	public void run() {
		Message message = new Message();
		message.arg1 = 1;
		handler.sendMessage(message);
	}
}).start();
  • msg最终进入MessageQueue。
final boolean enqueueMessage(Message msg, long when) {
	...
	//单链表的插入
    Message p = mMessages;
    msg.next = p;
    mMessages = msg;
    ...
    return true;
}
  • 主线程一直在轮询MessageQueue,取出刚入队的msg。msg持有handler的引用target,直接msg.target.dispatchMessage()。
public static final void loop() {
    Looper me = myLooper();
    MessageQueue queue = me.mQueue;
    while (true) {
        Message msg = queue.next(); // might block
        if (msg != null) {
            if (msg.target == null) {
                return;
            }
            ...
            msg.target.dispatchMessage(msg);
            msg.recycle();
        }
    }
}
  • dispatchMessage()内部调用handleMessage()。
public void dispatchMessage(Message msg) {
   		...
        handleMessage(msg);
}

还是有两个问题没有弄明白:子线程是什么时候结束的?代码从哪里开始进入主线程的运行环境的?为了彻底搞清楚这个问题,只能手写一个handler机制:

Handler.java

public class Handler {

    private MessageQueue mQueue;
    final Looper mLooper;
    public Handler() {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
    }

    public void handleMessage(Message msg) {

    }

    public void dispatchMessage(Message msg){
        handleMessage(msg);
    }

    public void sendMessage(Message msg){
        MessageQueue queue = mQueue;
        if (queue != null) {
            enqueueMessage(queue, msg);
        }
    }

    private void enqueueMessage(MessageQueue mQueue, Message msg){
        msg.target = this;
        mQueue.enqueueMessage(msg);
    }
}

Looper.java

public class Looper {

    static MessageQueue mQueue;
    private static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    private Looper() {
        mQueue = new MessageQueue();
    }


    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

    public static Looper myLooper() {
        return sThreadLocal.get();
    }

    public static void loop(){
        System.out.println(Thread.currentThread().getName() + ":进入loop()");
        Looper looper = myLooper();
        for(;;){
            Message msg = looper.mQueue.next();
            if(msg == null){
                continue;
            }
            msg.target.dispatchMessage(msg);
        }
    }
}

MessageQueue.java

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

/**
 *  互斥队列的通用类
 */
public class MessageQueue {

    //声明阻塞队列
    private BlockingDeque blockingDeque = new LinkedBlockingDeque(50);

    /**
     * 入队(生产者)
     * @param msg
     * @return
     */
    public void enqueueMessage(Message msg) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        try {
            blockingDeque.put(msg);
            System.out.println(Thread.currentThread().getName() + ":msg " + msg.what + " 入队完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 出队(消费者)
     * @return
     */
    public Message next() {
        Message msg = null;
        try {
            System.out.println(Thread.currentThread().getName() + ":MessageQueue.next() ");
            msg = (Message) blockingDeque.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return msg;
    }
}

Test.java


public class Test {

    public static void main(String[] args) {
        Thread androidMain = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Handler handler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        System.out.println(Thread.currentThread().getName() + ":handleMessage " + msg.what);
                    }
                };

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 5; i++) {
                            Message message = new Message();
                            message.what = i;
                            handler.sendMessage(message);
                        }

                        System.out.println(Thread.currentThread().getName() + "运行结束");
                    }
                }).start();
                Looper.loop();
                System.out.println(Thread.currentThread().getName() + "结束运行");
            }
        }, "androidMain");
        androidMain.start();
    }
}

看下运行结果:
Handler到底是怎么实现子线程的Message到主线程下被处理的?

从结果中可以得到答案:子线程在所有消息都入队完成后,就结束执行了。主线程一直在运行,Looper#loop()方法体内,已经进入主线程了,无限循环调用MessageQueue#next()方法,next()方法和后面的dispatchMessage()都运行在主线程。

细心的读者会发现,主线程并没退出,这是因为使用了阻塞队列LinkedBlockingDeque。关于阻塞队列,后续再讨论。

从这个手写的Handler,可以发现,MessageQueue的入队方法在子线程中执行,出队方法在主线程中执行。也就是说,同一个对象的不同方法,可以运行在不同的线程中。根据这个原理,我们可以写个更加简单的,子线程给主线程发送消息的例子:

public class SimpleHandler {
    volatile Message msg; //注意这里的volatiler

    public void loopAndHandleMsg() {
        while (true) {
            if (msg != null) {
                System.out.println(Thread.currentThread().getName() + " 处理消息:" + msg.what);
                msg = null;
            }
        }
    }

    public void sendMsg(Message msg) {
        while (this.msg != null) {

        }
        this.msg = msg;
        System.out.println(Thread.currentThread().getName() + "消息:" + msg.what+"发送完成");
    }
}

//Messgae.java文件
public class Message {
    int what;
    Handler target;
}


//Test.java文件
public class Test {

    public static void main(String[] args) {
		        Thread androidMain = new Thread(new Runnable() {
		            @Override
		            public void run() {
		
		                SimpleHandler simpleHandler = new SimpleHandler();
		
		                new Thread(new Runnable() {
		                    @Override
		                    public void run() {
		                            Message message = new Message();
		                            message.what = 6666;
		                            simpleHandler.sendMsg(message);
		
		                            Message message2 = new Message();
		                            message2.what = 8888;
		                            simpleHandler.sendMsg(message2);
		
		                        System.out.println(Thread.currentThread().getName() + "运行结束");
		                    }
		                }).start();
		
		               simpleHandler.loopAndHandleMsg();
		               System.out.println(Thread.currentThread().getName() + "结束运行");
            }
        }, "androidMain");
        androidMain.start();
    }
     
}

运行结果:
Handler到底是怎么实现子线程的Message到主线程下被处理的?

其实,核心就是:Message的产生、发送、存储都是在子线程完成的,而Message的读取,处理是在主线程完成的。这样看来,是不是觉得Handler也没啥神秘的。

上一篇:Handler消息机制原理,能线程切换的原因


下一篇:安卓学习日记--页面布局