网上大神们关于Android消息异步机制的文章已经不少了,而且分析也很到位,我在这主要是为了记录我的体会,有错误的地方欢迎你们指正。
转载请注明:http://blog.csdn.net/Mr_immortalZ/article/details/51066869java
一.概述
Android的消息机制主要是指Handler的运行机制,Handler的运行须要底层的MessageQueue和Looper的支撑。
大体的运行过程以下图
这里以UI线程(即主线程)与其余线程的交互为例。web
MessageQueue用于存储消息(Message)队列(内部存储数据结构是链表)数组
Looper会以无限循环的方式去查找是否有新的消息(Message),有则处理,没有则等待。数据结构
ThreadLocal能够在不一样线程中互不干扰地存储并提供数据,经过ThreadLocal能够轻松获取每一个线程的Looper。并发
Handler用于post消息(Message)给其余线程,并完成从其余线程到UI主线程的调转异步
综上可知 除了Handler运行在主线程,其余三个(MessageQueue,Looper,ThreadLocal运行在子主线程)
为了更好的理解运行时的关系。咱们对这四者分别介绍,最后再作总结。svg
ThreadLocal
由上图可知,Handler要想将消息投递给子线程,则必须投递到该子线程对应的Looper中。那么对于一个Handler来讲,我怎么知道,我投递的消息是否投递到了A线程,而不是B线程呢,换句话说,Handler又是怎么和我想要的Looper创建起联系的呢?答案就是ThreadLocal!也正是ThreadLocal的存在,让队列与线程关联上了!函数
ThreadLocal在线程中的做用oop
ThreadLocal是一个线程内部的数据存储类,经过它能够在指定的线程中存储数据,数据存储后,只有在指定的线程中才能够获取到该数据,其余线程没法获取(换而言之,当某些数据是以线程为做用域而且不一样线程具备不一样的数据副本时,就能够考虑使用ThreadLocal)。例如:对于Handler来讲,它须要获取当前线程的Looper,很显然Looper的做用域就是线程而且不一样线程具备不一样的Looper,这个时候经过ThreadLocal就可让Handler轻松获取到想要线程的Looper,从而进行其余操做。(之因此说轻松,是由于若是不采用ThreadLocal的方式来获取Looper,系统为了让Handler来获得想要的线程的Looper,则必须提供一个全局的哈希表供Handler查找指定线程的Looper,这样一来就必须提供一个相似LooperManager的类的管理,增长了使用成本)post
ThreadLocal其余场景下做用
ThreadLocal另外一个使用场景是复杂逻辑下的对象传递,好比监听器的传递,有些时候一个线程中的任务过于复杂,这可能表现为函数调用栈比较深以及代码入口的多样性,在这种状况下,咱们又须要监听器可以贯穿整个线程的执行过程,这个时候能够怎么作呢?其实就能够采用ThreadLocal,采用ThreadLocal可让监听器做为线程内的全局对象而存在,在线程内部只要经过get方法就能够获取到监听器。而若是不采用ThreadLocal,那么咱们能想到的多是以下两种方法:第一种方法是将监听器经过参数的形式在函数调用栈中进行传递,第二种方法就是将监听器做为静态变量供线程访问。上述这两种方法都是有局限性的。第一种方法的问题时当函数调用栈很深的时候,经过函数参数来传递监听器对象这几乎是不可接受的,这会让程序的设计看起来很糟糕。第二种方法是能够接受的,可是这种状态是不具备可扩充性的,好比若是同时有两个线程在执行,那么就须要提供两个静态的监听器对象,若是有10个线程在并发执行呢?提供10个静态的监听器对象?这显然是难以想象的,而采用ThreadLocal每一个监听器对象都在本身的线程内部存储,根据就不会有方法2的这种问题。
ThreadLocal之因此有这么奇妙的效果,是由于不一样线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,而后再从数组中根据当前ThreadLocal的索引去查找出对应的value值,很显然,不一样线程中的数组是不一样的,这就是为何经过ThreadLocal能够在不一样的线程中维护一套数据的副本而且彼此互不干扰。
MessageQueue
感受消息队列为啥好说的,主要操做就是增删。值得注意的就是:消息队列的内部实现并非真正的队列,而是用单链表(明显链表的增删操做易于队列)
Looper
looper主要方法:
这里看看hongyang大神对Looper两个主要方法prepare(),loop()的分析(截图上是个人理解)
Handler
消息的发送能够用过post或send一系列方法来实现,而post的一系列方法最终是经过send一系列方法来实现的。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int what) //不须要自行new message,推荐
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
由上可知,Handler发送消息仅仅是想消息队列插入了一条消息。MessQueue的next方法会返回这条消息给Looper,Looper通过取消息将取得的消息交给Handler处理,即
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //在post消息中,咱们进行了new Runnable操
handleCallback(msg); //做,走这个分支
} else { //直接在建立Handle的构造函数中就进行了new Callback操做
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可见咱们在建立Handler实例时有两种方法
未完待更新