Android 消息机制之 handler、messageQueue、looper深入剖析

        大家好,我是听者,耳听心受的听,孙行者的者,感谢大家阅读我的文章。今天继续为大家带来Android消息机制剖析。相信每一个开始接触Android开发的兄弟姐妹们在接触到线程之间通信时对于handler、looper、message、messageQueue都可能会懵逼,至少我是这样的,当拿到毕业证的第二天去某大型企业面试,面试官的第一个问题就是这个,背会了某度查询的结果,果不其然还是挂了,废话不说,直接进入主题。

       首先先谈谈handler,handler是怎么处理消息的呢?内部是怎样实现的呢?handler包含两个重要的成员变量mLooper和mQueue,只要我们搞清楚其来源和去向基本就知道发生了什么,看一段代码:

  public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

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

从红色注释的代码中显然可以看出来mLooper和mQueue都是在handler的构造方法中赋值的并且是从looper中得到的,至于Looper.myLooper()是怎么实现的,咱们在这里留一个疑问(疑问一),下来我们再看一段代码,

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

在handler中不管是调用handler.sendmessage()还是调用handler.post()方法其最终是将runnable,看红色代码一是将当前的handler赋值到message的target上带走,红色2是将该message交给messageQueue处理(这里的messageQueue就是handler的成员变量)。这样handler结束了,对,handler就这么简单。

接下来我们看一下messageQueue实现了什么和enqueueMessage()中做了什么。messageQueue从字面意思看是一个消息队列,但是在messageQueue中只包含一个Message类型的mMessage成员变量,那这又是为什么呢?不要着急,我们看一段代码,这是enqueueMessage()中的一段核心代码:

           msg.when = when

           Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }

                msg.next = p;
                prev.next = msg;

            }

通过红色代码可以看出message的实现是一个队列的实现方式,其包含一个message类型的成员变量next,该next指向列表的下一个节点,而messageQueue的成员变量mMessage是该列表的头节点。再看一下蓝色代码,通过循环遍历改mMessage消息队列,跳出循环的条件是下一个节点为空或者 when < p.when,至于这个when是什么线留个疑问,很明显,当跳出循环以后,p指向的下一个节点,prev指向的是前一个节点,将当前的msg插入二者中间(蓝色代码),没有看懂这个循环大家可以在纸上划拉一下即可。现在我们看一下when到底是什么?第一段代码是将enqueueMessage()传入的when赋给了当前message的when,在看一段代码:

sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)

红色代码是当前系统时间+延迟时间,那么这个when就是指在哪个时间点执行这个message,如果没明白这里留个疑问,接下来我们再看messageQueue的next()方法做了些什么操作。由此可见messageQueue是按照时间的执行先后排序的(结合 when < p.when)。代码:

            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;

            if (now < msg.when) {
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }

              if (mQuitting) {//当退出的时候返回空,后面用
                    dispose();
                    return null;
                }

这就是messageQueue中next()方法的核心代码,前面我们知道了messageQueue是按照执行时间先后排序的,这里就是先用当前的时间now和第一message的when比较如果还不到其执行时间等待 nextPollTimeoutMillis 时间再来执行,next()方法是通过两个native方法阻塞的,至于怎么实现需要看native的代码,而遍历还是通过循环的,全部代码可以看一下源码,当到了该message执行的时间,将其从列表头节点取出来,返回出去。至于返回出去做了什么我们接下来看一下looper。

在介绍Looper之前我觉得有必要和大家分享另一个类threadLocal,ThreadLocal类的诞生给解决多线程并发的一个新思路。下面看一些核心代码:

threadLocal的set方法:

public void set(T value) {//threadLocal的set方法
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

threadLocal的values()方法:

Values values(Thread current) {
        return current.localValues;
    }

返回一个Thread的成员变量。

initializeValues方法

Values initializeValues(Thread current) {
        return current.localValues = new Values();
    }

从上述代码中可以看出来,threadLocal创建一个values对象,将其赋值到Thread的成员变量localValues中,再讲value值加入到该values中,具体怎么实现不深究,只要了解当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

知道这个概念以后咱们接下来再研究Looper,当为指定线程创建一个looper时大家都知道先调用Looper.prepare(),看一下其实现:

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

new一个Looper对象,并将其添加到sThreadLocal中,再看一下初始化Looper对象时做了哪些操作:

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

创建了一个messageQueue对象,得到当前Looper的线程,还记前面handler中的messageQueue吗?就是这里创建的,在这里我们得出一个结论,没有Looper的Thread当创建Handler时会crash。接下来就应该调用Looper.loop(),在loop()方法中又做了哪些事情呢?接下来我们看一下loop()的核心代码:

 for (;;) {
            Message msg = queue.next();
            if (msg == null) {
                return;
            }

            msg.target.dispatchMessage(msg);
           
        }

根据代码可以看出当next返回空的时候looper结束,不为空的时候调用handler.dispatchMessage(msg)方法(还记得msg.target=this,不记得回handler看看)。这样一个消息传递机制就完成了,那什么时候返回空呢?还记得当时在messageQueue的时候那段加粗代码,当退出messageQueue的时候返回null,所以这里要得出一个结论,当我们再子线程中创建了Looper,在确定线程结束的时候要调用looper的quit()

总结一下Android的消息机制:

step1:在线程中创建一个Looper对象,调用其loop方法形成死循环,读取messageQueue中的消息。

step2:创建一个handler对象。

step3 :在其他线程中调用handler.sendMessage()等方法,将message加入到Looper的messageQueue中,因为loop()是在创建Looper的线程中执行,所以handler的dispatchMessage回到了创建handler对象的线程中执行。完美完成了线程间通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值