任何一个APK都是从framework层的ActivityThread的main()函数中开始执行,接着调用prepareMainLooer()为UI线程创建一个消息队列MessageQueue.并执行Looper.loop().
Handler消息机制的原理是什么了?我们先来写一个程序看看。
首先看new Handler().做了什么
可以看出在new Handler()中获取了Loop,messagequeue,callback,等对象。
接下来看handler.sendEmptyMessage(DATA)做了什么。
通过源码可以看出,handler.sendEmptyMessage(DATA)最后走到了queue.enqueueMessage(msg, uptimeMillis), queue是消息队列MessageQueue,现在就要知道消息队列的enqueueMessage(msg. UptimeMills)做了些什么,查看源码,这个方法的源码太长,且不易理解,最后通过查看资料可知,这个方法主要是以一种链式的结构将消息msg存放在消息队列messageQueue中,这样我们就知道,原来handler.sendEmptyMessage(DATA)的作用就是将消息msg放到MessageQueue中。
这样就完了,但是我们是如何来不断的获取消息,然后处理消息的了,这里就要用到Looper对象了,首先我们要知道一点,一个线程中存在Looper对象,则必定存在一个MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象,线程,Looper,MessageQueue是1:1:1的关系。在android系统中,除了主线程有默认的Looper对象,其它线程默认是没有Looper对象,如果想让我们新创建的线程拥有Looper对象,我们首先要调用Looper.preare(),然后在调用Looper.loop()方法,倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象,在这里有一点需要注意的是,假如Looper对象位于主线程中,则二者获取的是同一个对象。
上面我们谈到,只有主线程中才会默认有一个Looper对象,这是为什么了?首先我们要知道,任何一个APK都是从framework层的ActivityThread的main()函数中开始执行,来看看main()中做了什么
上面可以看出,在main中首先调用了Looper.prepareMainLooper();接着new 了一个ActivityTHread 对象,紧接着就是调用Looper.loop,接下来我们看看这几个方法具体干了些什么,首先看看Looper.prepareMainLooper()
首先调用了prepare(false),看看这个方法做了什么
这个方法中有个ThreadLocal对象,调用了这个对象的get,与set方法,那么这个ThreadLocal又是个什么东西了,通过查看资料了解到,ThreadLocal并不是一个thread,而只是thread的一个局部变量,它里面的原理其实很简单,在ThreadLocal中封装了一个Map对象,set(new Looper(quitAllowed))方法中其实就是以当前的线程为键,以new Looper(quitAllowed)对象为值放入map集合中,调用get()方法是,先获取当前线程对象presentthread,再通过presentthread对象从map集合中取出值。接下来就很清楚了,第一次调用sThreadLocal.get()方法时肯定为null,接着就会在ThreadLocal中以主线程对象为键,new 一个Looper对象为值放入Map中,接下来在prepareMainLooper中会执行sMainLooper=myLooper(),看看myLooper中做了什么
这样就很清楚了,myLooper()方法其实就是返回一个Looper对象,也就是我们刚刚在prapare(false)中new的Looper对象,这样Looper.prapareMainLooper()其实就是为主线程创建了一个Looper对象。
接下来我们看看Looper.loop()(都是静态方法可以直接调用)做了什么
最核心的就是上图的4个地方,首先看看
1:获取到Looper对象 Looper = me = myLooper();
2: 获取到消息对象 MessageQueue queue = me.mQueue;
3:获取到下一个消息 Message msg = queue.next();
4:将消息分发出去 msg.target.dispatchMessage(msg);
大家可以看到3处获取下一个消息实际上是在一个for循环中,并且是一个死循环,就是说不停的从消息队列中抽取消息,只要消息不为空就不会跳出循环,接着就是分发消息了,来看看msg.target.dispatchMessage(msg)做了些什么,这里要指出的是msg.target得到的是一个handler对象,实际上在我们获取消息调用Message message = handler.obtainMessage()时就会为每一个消息设置一个target的,这个target就是调用它的handler,代码如下
接下来就很清楚了,直接看看handler的dispatchMessage(msg)
最后可以看到调用了handleMessage(msg)(这里我只讨论了else里面的情况,剩下的情况大家可以自己去看)
源码中这是一个空方法,一般需要我们去重写这个方法,自己想怎么处理消息就怎么处理。这样似乎就完了,大家是不是有一个疑问,就是我刚刚说的,这一切能顺利的进行下去是因为在3处得到的消息不为空,但是我们知道主线程的Looper.loop()是在ActivityThread的Main方法中调用的,这时消息队列中可没有消息啊,一旦获取到的msg为空,直接return ,for循环就会跳出,方法loop()就这样结束了,这怎么能行了?方法loop()可以结束吗,一旦结束了,那么接下来还有消息怎么办了,谁来从消息队列中抽取消息了,我们可从来没有在主线程中自己亲自调用过Loop()方法,这就需要看看3处Message msg = queue.next()到底做了什么,看msg到底能不能为null,什么时候可以为null。
在next方法中首先就来了一个for循环,和loop()方法中一样,也是个死循环,那么什么时候可以结束这个循环了,看2处当mQuiting为true时就会return null ,这个时候next()方法就会返回一个空值,对应着loop()中就会跳出for的死循环,结束抽取消息,那么这个mQuiting是在什么地方赋值的了?
通过查看源码,可知是在MessageQueue.quit(boolean)中赋值的,也就是说只有当我们调用MesssageQueue.quit(false)时,Loop()方法才会结束,实际上Looper也有一个quit方法,我们来来Looper.quit()做了什么
这样大家就很清楚了吧,实际上mQuiting的初始值是false,接下来代码继续往下走来到3处。首先判断msg!=null,如果不成立则开始下一个循环,成立则来到4处,再次判断msg是否为null,这里肯定是不为null了,前面已经判断过了,接着就是5处的返回msg了,这里返回的msg肯定不为null了,所有在loop()方法中,只要我们不调用Looper.quit(),那么queue.next()就一定不会返回一个null的msg,至此handler机制分析完毕。
最后来张图方便理解