码迷,mamicode.com
首页 > 其他好文 > 详细

handler机制原理分析(适合初学者)1.0

时间:2016-09-04 23:52:23      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

     任何一个APK都是从framework层的ActivityThreadmain()函数中开始执行,接着调用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对象,线程,LooperMessageQueue1:1:1的关系。在android系统中,除了主线程有默认的Looper对象,其它线程默认是没有Looper对象,如果想让我们新创建的线程拥有Looper对象,我们首先要调用Looper.preare(),然后在调用Looper.loop()方法,倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象,在这里有一点需要注意的是,假如Looper对象位于主线程中,则二者获取的是同一个对象。

上面我们谈到,只有主线程中才会默认有一个Looper对象,这是为什么了?首先我们要知道,任何一个APK都是从framework层的ActivityThreadmain()函数中开始执行,来看看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)newLooper对象,这样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,代码如下

 技术分享

技术分享

 

接下来就很清楚了,直接看看handlerdispatchMessage(msg)

 技术分享

最后可以看到调用了handleMessage(msg)(这里我只讨论了else里面的情况,剩下的情况大家可以自己去看) 

源码中这是一个空方法,一般需要我们去重写这个方法,自己想怎么处理消息就怎么处理。这样似乎就完了,大家是不是有一个疑问,就是我刚刚说的,这一切能顺利的进行下去是因为在3处得到的消息不为空,但是我们知道主线程的Looper.loop()是在ActivityThreadMain方法中调用的,这时消息队列中可没有消息啊,一旦获取到的msg为空,直接return for循环就会跳出,方法loop()就这样结束了,这怎么能行了?方法loop()可以结束吗,一旦结束了,那么接下来还有消息怎么办了,谁来从消息队列中抽取消息了,我们可从来没有在主线程中自己亲自调用过Loop()方法,这就需要看看3Message msg = queue.next()到底做了什么,看msg到底能不能为null,什么时候可以为null

 技术分享

 

 

next方法中首先就来了一个for循环,和loop()方法中一样,也是个死循环,那么什么时候可以结束这个循环了,看2处当mQuitingtrue时就会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()就一定不会返回一个nullmsg,至此handler机制分析完毕。 

 最后来张图方便理解

技术分享

 

handler机制原理分析(适合初学者)1.0

标签:

原文地址:http://www.cnblogs.com/tuyong1012341/p/5840519.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!