Android Handler,MessageQueue,Looper源码解析

本文主要针对Handler机制原理进行源码分析,如果对Android的Handler机制不熟悉的可以查看Android Handler机制

总结来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制。那这种机制如果仅仅通过一个Handler是无法完成任务的,还需要Looper、MessageQueue、Thread等的协作才能完成这一整套的异步消息循环处理机制。这几个类之间的关系可以通过下图(图片引自孙群)来说明:

è¿éåå¾çæè¿°

首先需要有一个Thread,Looper和MessageQueue都构建在Thread之上,Handler又构建在Looper和MessageQueue之上,通过Handler间接地与下面这几个类进行合作,来完成这一整套的异步消息循环处理机制。

下面我们通过源码(API 25)一步一步的进行分析:

1、MessageQueue:

下面会多次谈到MessageQueue,所以先说提前说下:

MessageQueue是一种数据结构,即我们常说的消息队列,用来存放消息,需要注意的是每个线程最多只能由一个MessageQueue对象。MessageQueue有两个比较重要的方法:enqueueMessage()与next()方法。enqueueMessage()方法主要用于将消息(Message)存放入消息队列MessageQueue中;next()方法主要是从消息队列中阻塞式的取出一个Message。创建线程的时候,并不会主动创建MessageQueue,需要一个Looper对象对MessageQueue进行管理。创建主线程的时候,会默认创建一个Looper,在Looper对象的创建,将自然创建一个MessageQueue;而在子线程的创建中,并不会自动创建Looper,所以也就不会创建MessageQueue对象,在调用Looper.prepare()的时候才会自动创建该线程的消息队列。

2、Looper:

Looper是一个final类,主要的方法有两个prepare()、loop(),是MessageQueue的管理者,每个MessageQueue都不能脱离Looper而存在,同时一个Looper对象跟一个线程相关联,主线程有默认的Looper,而子线程没有,但可通过Looper.prepare()创建:

<1> prepare()方法:

    public static void prepare() {
        prepare(true);
    }
    private static void prepare(boolean quitAllowed) {
        //注释2
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //注释1
        sThreadLocal.set(new Looper(quitAllowed));
    }

注释1:

prepare方法主要生成一个自身Looper对象,并将其放置ThreadLocal(可以在一个线程中存储变量)对象中。

注释2:

判断了ThreadLocal.get()是否为空,如果不为空的话就抛出异常。这也说明,prepare方法不能调用两次,即一个线程中的Looper只能有一个实例对象。

再往下看Looper的构造函数如下:

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

可以看到,Looper的构造函数中,生成了一个MessageQueue(消息队列)对象和当前Thread对象。

<2> loop()方法:

public static void loop() {
        //注释1
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        
        //注释2
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            //......此处省略n行代码......
            
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            //......此处省略n行代码......

            msg.recycleUnchecked();
        }
    }

注释1:

通过myLooper()方法可以从之前存储到ThreadLocal实例中的当前Looper对象me,源码如下:

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

如果me为空,抛出异常,通过异常可以得知,在执行loop()方法之前,我们必须先执行prepare()方法。

然后将该Looper对象构造函数中生成的MessageQueue对象mQueue赋值给本地MessageQueue对象queue。

注释2:

这里是一个无限for循环,通过MessageQueue的next()的方法来不断的获取已存储到MessageQueue的Message对象msg。如果取出的一条msg是null,那么便阻塞循环。如果msg不为空,那么执行msg.target.dispatchMessage(msg)方法来分发消息。这里的target其实就是Handler对象。

看到这里大家可能要问,为什么主线程不会因为Looper.loop()里的死循环卡死?(参考

这里插入一点知识,做一下简要说明: Android应用程序的主线程在进入消息队列的循环过程前,会在内部创建一个Linux管道(pipe)【其实是创建了一个Binder线程】,这个管道的作用是Android 应用程序的主线程在消息队列为空时可以进入空闲等待状态,并且使得应用程序的消息队列有消息处理时唤醒应用程序的主线程。

 

如上分析,我们可以对Looper进行个小总结:

1、通过prepare方法,可以与当前线程绑定,保证一个线程中只有一个Looper实例,一个Looper实例中,只有一个MessageQueue实例。

2、通过loop方法,可以无限循环地从MessageQueue中拿取Message对象,如果消息不为空,则交给Handler的dispatchMessage方法来派送消息。到此我们便可以顺水推舟来查看Handler的dispatchMessage源码,来查看到底Handler是如何来发送消息的。

3、Handler:

我们直接来看下Handler的diapatchMessage方法:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            //注释1
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                //注释2
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //注释3
            handleMessage(msg);
        }
    }

首先判断了msg.callback方法是否为空,这个msg.callback是什么呢。首先我们来回顾下Handler在子线程中发送消息的较常使用的两种方式。

第一种是:

mHandler.sendMessage(msg);

第二种就是:

mHandler.post(new Runnable() {
          @Override
           public void run() {
        //主线程UI更新
    }              
});

通过查看post源码:

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

上面注释1中的msg.callback即是通过post传递进来的Runnable对象。

到这里我们就比较清晰了。首先Handler发送消息的时候,首先检查是否有mHandler通过post方法传递过来了Runnable对象,如果有,则直接回调该Runnable的run()方法,如下:

    private static void handleCallback(Message message) {
        message.callback.run();
    }

我们在接着dispatchMessage方法往下看,如果msg.call为空,那么此时注释2处出现了个mCallback,那么这个mCallback又为何物呢。

我们看下Handler的构造函数,其中有一个:

    public Handler(Callback callback) {
        this(callback, false);
    }
public Handler(Callback callback, boolean async) {
        
        //.....此处省略n行代码......

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //注释2
        mQueue = mLooper.mQueue;
        //注释1
        mCallback = callback;
        mAsynchronous = async;
    }

由构造函数的注释1可以得知,mCallback方法是由Handler内部的Callback赋值过来的。此Handler构造函数使用方式如下:

    private static Handler mHandler = new Handler(new Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            //更新UI操作
            return true;
        }
    });

通过上面dispatchMessage方法注释2处得知,如果此handlerMessage返回true,则直接调用完此回调后终止。否则继续往下执行,我们再往下看注释3此处调用的就是我们常用的Handler本身的handleMessage方法,使用方式如下:

    private static Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //更新UI操作
        }
    };

至此通过对上面dispatchMessage方法注释1、2、3的分析,我们可以做一个小结:

即为了能够使Handler处理Message,我们大致有三种实现方式:

<1>通过Hander的post方法,直接传递一个Runnable对象。

<2>向Handler的构造函数中传递一个Handler.Callback对象,并实现其handleMessage方法。

<3>无需向Handler构造函数中传递任何对象,只需重写Handler的handleMessage方法。

至此,我们再回过头来看一下上面说到的发送消息的两种方式sendMessage与post方式,通过查看源码可知两者最终都会走到如下方法:

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

进而进入到sengMessageAtTime方法

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //注释1
        MessageQueue queue = mQueue;
        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);
    }

通过注释1得知,mQueue赋值给了本地queue,并作为了enqueueMessage的参数传入。此mQueue是哪个消息队列呢。通过上面Handler构造函数注释2的源码

mQueue = mLooper.mQueue;

可知,此消息队列即是原Looper中生成的消息队列(mQueue)。至此Handler、Looper、MessageQueue均已关联起来。

我们接着往下看enqueueMessage方法:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //注释1
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

注释1可知,将msg.target绑定为当前的Handler。继续往下看,再通过Handler绑定的MessageQueue,通过调用其enqueueMessage方法,将消息排列入MessageQueue。

以上就是异步消息处理机制的源码解析,是不是对整个机制有所了解了呢,欢迎评论交流。

参考:

【鸿洋】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1107/523.html

https://blog.csdn.net/iispring/article/details/47180325

发布了95 篇原创文章 · 获赞 195 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/u012440207/article/details/88667195