标签:
# 标签: 读博客
对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖.
Handler 、 Looper 、Message 这三者都与Android异步消息处理线程相关的概念。
异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。
说了这一堆,那么和Handler 、 Looper 、Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。
二.源码分析
说道Handler也是面试常客了... 当然这也是Android中比较重要的一个部分。
就按他们出场的先后顺序来分析吧(源码基于API 19,建议边看边对照源码)
最先是Looper... App启动时 会自动调用Looper.prepare()方法
那么我们来看看Looper.prepare()是做什么的呢..
public static void prepare(){ prepare(true); }
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)); }
如果当前线程当中已经有Looper了 就抛出异常(这也是为什么一个线程只能有一个Looper实例 ,只有一个MessageQueue实例的原因) ;
如果没有就初始化一个Looper对象放入当前线程中
说明一下:sThreadLocal是什么..看源码便知 是用来存放线程的Looper对象的(当前线程只能取当前线程存的)
static final ThreadLocals<Looper>ThreadLocal = new ThreadLocal<Looper>();
再看看Looper的构造方法
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
构造方法中,最主要的就是创建了一个MessageQueue,这东西是干嘛用的呢? 存放Handler发来的消息(接下来会证实),所以俗称 消息队列。
继续看Loop()方法 这个就不贴全部源码了 挑重要部分进行分析...(建议参照源码进行阅读)
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;
拿到当前线程中的Looper实例(如果Looper实例为空就会抛出异常)再去拿Looper中的MessageQueue实例
for (;;) { Message msg = queue.next(); if (msg == null) { return; } msg.target.dispatchMessage(msg); msg.recycle(); }
依然只上了关键代码...
一个无限循环 不断从MessageQueue实例中获取下一个Message,未获取到便返回;
获取到Message实例则调用msg.target.dispatchMessage(msg); 把消息交给Message实例的target的dispatchMessage方法处理,看到这里可能会有疑问了,msg的target是什么? 查看源码可以发现就是Handler对象,下面分析Handler的时候会说道;最后释放msg
小结:Looper的主要作用
1.与当前线程绑定,并保证一个线程中只有一个Looper实例,从而保证了一个线程中只有一个MessageQueue实例。
2.loop()方法,就是不断的从MessageQueue中取出消息,并交给msg.target.dispatchMessage(msg)去处理(交给Handler去处理,接下来会细说)
我们用Handler之前都会初始化一个Handler对来更新UI线程...等等. 上源码. 来看看Handler是如何与MessageQueue关联上的 ,还有在非UI线程中是如何将消息发送到MessageQueue当中去的
来看看Handler的构造方法
public Handler(Callback callback, boolean async) { // 省略相关检查代码 mLooper = Looper.myLooper(); // Tag1 if (mLooper == null) { throw new RuntimeException( "Can‘t create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; //Tag2 mCallback = callback; mAsynchronous = async; }
Tag1 调用了Looper.myLooper() 前面Looper分析环节说到了 这是从当前线程中拿出Looper实例
Tag2 将Looper实例中的MessageQueue实例取出来
此时,Handler和MessageQueue就关联上了
辣么? 我们我们在非UI线程中,是如何将消息传递给MessageQueue的呢... 继续看源码
平时通过Handler发送一条Message是不是通过
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }
public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 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); }
看到这里,大家想起了什么? 没错 mQueue就是Handler初始化的时候 从当前线程取出的Looper中取出来的MessageQueue
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
msg.target = this; ?? msg.target赋值为this,(大家还记得在前面Looper.loop()方法中不断从消息队列中读消息 然后调用 msg.target.dispatchMessage(msg)来处理信息 ) ;也就是将当前Handler实例作为msg的target属性,最终调用了queue.enqueueMessage(msg, uptimeMillis)方法 将消息存入MessageQueue中去 ; 换一句话说 Handler发出来的消息 最终保存到了MessageQueue中去
现在消息已经存入了MessageQueue中,前面提到Looper.loop() 会不断的读取MessageQueue中有无信息,有信息会通过msg.target(也就是Handler) 来调用dispatchMessage(msg) ,来看看源码
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
最后调用了handleMessage(msg); 看到这里是不是感觉很熟悉了 我们再快看看handleMessage(msg)的源码
public void handleMessage(Message msg) { }
里面什么都没有? 什么情况? 回想一下,平时我们初始化一个Handler实例 是不是都会复写handleMessage方法? 因为最终回调是由我们来控制。说道这里 整个异步消息处理的流程已经梳理完了 让我们来总结一下
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
------------------------------------------------------
内容参考Hongyang大神的博客... 概念和总结属于搬运工... 源码分析是独立编写,在洋神的基础上加上了一些自己的理解... 希望这篇总结帖对大家在学习Android的道路上 有所帮助...
-
补充,原文基本上说清楚了架构,然而参考代码是4.3并且谈东西没有图,也米有详细代码。
参考即可。
Android异步消息处理 Handler Looper Message关系源码分析
标签:
原文地址:http://my.oschina.net/wizardmerlin/blog/510873