Android Handler消息机制源码分析

我们知道子线程发送消息给主线程是使用Handler的,基本用法就是在主线程中创建Handler、在子线程通过handler.sendMessage()发送消息、handlerMessage()中处理消息。但是这之间的具体过程可能很多人不清楚,其实就是通过Looper来无限循环处理消息的,Looper也可以称为轮询器。
UI线程的Looper是在ActivityThread->main()方法中创建的,也就是说UI线程的Looper是默认创建的,不需要我们自己操作,同时这个main函数也是APP的入口。我们看下源码:

        public static void main(String[] args) {
            ...
            Looper.prepareMainLooper();//创建主线程的Looper

            ActivityThread thread = new ActivityThread();
            thread.attach(false);

            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();//获取主线程的Handler
            }
            Looper.loop();//开始消息循环,这是一个死循环,后面会讲到
        }

Looper.prepareMainLooper()就是在主线程中创建Looper并将其添加到sThreadLocal中,sThreadLocal的作用就是使得不同的线程不能访问别的线程的消息队列

    public static void prepareMainLooper() {
        prepare(false);//创建Looper,false的作用是指定此线程不能被终止
        synchronized (Looper.class) {
            ...
            sMainLooper = myLooper();//myLooper()方法通过sThreadLocal.get()获取创建的Looper,并赋给sMainLooper(主线程的Looper)
        }
    }

    private static void prepare(boolean quitAllowed) {
        ...
        sThreadLocal.set(new Looper(quitAllowed));//创建Looper并将其添加到sThreadLocal中
    }

创建Looper对象时,会同时创建MessageQueue,

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

现在主线程Looper和MessageQueue都创建好了,但是怎么发送和处理消息呢?答案就是使用Handle处理,我们先看下Handler的构造函数:

    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();//获取Handler所处线程的Looper,mLooper为空则抛出下述异常
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//获取消息队列
        mCallback = callback;
    }

从上述代码可以看出Handler创建时会关联其所处线程的Looper和MessageQueue,所以当子线程需要发送消息给主线程时,Handler必须在主线程中创建,这样handlerMessage()才会在主线程执行。

主线程若发消息给子线程,则Handler需在子线程中创建,但是前提子线程必须要自己创建好Looper和MessageQueue,否则就会抛出上述异常。

现在理清了Handler与Looper和MessageQueue的关系,我们还得知道怎么发送和处理消息。
我们知道创建Handler是必须要实现handlerMessage()方法,如下所示:

    class MyHandler extends Handler {
        @Override
        public void handlerMessage(Message msg) {
            //更新UI
        }   
    }

也就是说我们发出的消息最终会被handlerMessage()方法处理,但是handlerMessage()是怎么被调用的呢?其实就是当我们执行Handler.sendMessage()或mHandler.post()等方法发送Message时,最终都是调用sendMessageAtTime()方法,这个方法将Message添加到MessageQueue中。

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//获取MessageQueue
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);//将Message添加到MessageQueue中
    }

前面讲了Looper.loop()方法时无限循环的,只有消息队列中有消息就会被处理。

    public static void loop() {
        final Looper me = myLooper();//获取Looper
        final MessageQueue queue = me.mQueue;//获取消息队列

        for (;;) { //无限循环
            Message msg = queue.next(); // 获取消息(might block)
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            msg.target.dispatchMessage(msg);//处理消息,msg.target是目标Handler
            msg.recycleUnchecked();//回收消息
        }
    }

注意,每个Message都有一个target变量,用于指向处理消息对应的Handler,因为一个线程可能有多个Handler,通过target来区分。

从上面代码可以看出处理消息实际上是调用Handler的dispatchMessage()方法,而dispatchMessage()方法就是调用handlerMessage()处理消息。

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//处理消息
        }
    }

总结一下:主线程会默认创建Looper,然后new Looper()时会创建MessageQueue,子线程发消息给主线程的过程是:在主线程创建Handler对象,在子线程通过Handler.sendMessage()等方法发送消息,此消息被添加到handler对象所在线程的MessageQueue中,然后Looper.loop()无限循环地从MessageQueue中取消息并且调用Handler的dispatchMessage()方法将消息发送给handleMessage()处理。我们可以在handleMessage()方法中更新UI等。

若需要主线程发消息给子线程,则Handler需在子线程中创建,但是前提子线程必须要自己创建好Looper和MessageQueue,否则就会抛出异常。可以参考下述示例:

    new Thread {
        Handler handler = null;
        public void run() {
            Looper.prepare();//创建此线程的Looper
            handler = new Handler();
            Looper.loop();//启动消息循环
        };
    }.start();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值