在平常开发中主要做用于两方面:
一、在UI线程进行耗时操做时,将耗时操做抛到子线程进行处理,不然容易ANR。
二、在子线程中刷新UI。
java
Handler、Looper、MessageQueue 和 Message 是组成Handler通讯机制的基础。android
Handler的使用基本如如下代码所示,或者继承Handler重写handleMessage,处理不一样what标识的Message。不是本文讨论的重点,不作过多叙述。设计模式
//建立子线程Handler
HandlerThread mHandlerThread = new HandlerThread("daqi");
mHandlerThread.start();
Handler mHandler = new Handler(mHandlerThread.getLooper());
//建立Message
Message message = mHandler.obtainMessage();
//发送Message
mHandler.sendMessage(message);
//post
mHandler.post(new Runnable() {
@Override
public void run() {
}
});
复制代码
建立Handler,并绑定Looper -> Handler发送Message -> Message存储到Looper的MessageQueue中 -> Looper在MessageQueue中拿取顶部Message -> 将Message发送给目标Handlerbash
Handler、Looper、MessageQueue 和 Message的关系:
异步
带着问题看源码:
一、Looper如何确保线程中只有一个单例。
async
二、为何建议使用Handler#obtainMessage()获取Message对象,而不是直接new。
ide
三、Handler的sendMessage() 和 post()有什么区别。
函数
四、Looper如何管理Message队列(即前后发送不一样延迟时间的Message,Message队列如何排序)。
oop
五、removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什么。
源码分析
Handler在建立时,默认构造方法会绑定当前线程。因此咱们选择先从Handler的默认构造方法看起。
#Handler.java
//无参构造函数
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//....
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
}
复制代码
建立Handler对象时,无参构造函数会获取当前线程的Looper并获取到其MessageQueue存储到Handler自身变量中。
但咱们也观察到,若是没有Looper的Thread中建立,会抛出RuntimeException,并告诉你该线程无Looper。
从Handler的默认构造方法中得知,在建立Handler前,须要先在当前线程中建立Looper对象和MessageQueue对象。而建立Looper对象和MessageQueue对象只须要调用以下方法:
Looper.prepare();
Looper.loop();
复制代码
prepare的意思是准备,便可以猜想Looper是在Looper#prepare()中初始化的,因此先从Looper#prepare()的源码看起:
#Looper.java
//主要用于做为存储的Looper实例的key。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//ThreadLocal#get()获取当前线程的looper对象
if (sThreadLocal.get() != null) {
//若是Looper已经实例化完,则会抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
//若是以前当前线程没有初始化过Looper,则建立Looper并添加到sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
复制代码
咱们发现Looper#prepare()调用重载函数Looper#prepare(boolean)。在这方法中,Looper会被初始化。查看Looper私有构造函数,发现Looper会初始化MessageQueue并存储当前线程。
而Looper被初始化是有一个前提的,即sThreadLocal.get() == null。不然会抛出RuntimeException,并告诉你该线程只能建立一个Looper对象。
sThreadLocal是Looper类中定义的一个静态ThreadLocal常量。继续查看ThreadLocal#get()和ThreadLocal#set()方法。
#ThreadLocal.java
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//线程中存在一个ThreadLocal.ThreadLocalMap类型的变量
//根据当前线程thread获取到对应的ThreadLocal.ThreadLocalMap变量。
ThreadLocalMap map = getMap(t);
if (map != null) {
//this表示Looper类中的静态ThreadLocal常量sThreadLocal
//由于sThreadLocal是静态常量,做为“key”,确保变量为单例。
//根据sThreadLocal获取到对应的ThreadLocalMap.Entry值。
ThreadLocalMap.Entry e = mapgetEntry(this);
if (e != null) {
//从ThreadLocalMap.Entry中获取到对应的Looper,
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//线程中存在一个ThreadLocal.ThreadLocalMap类型的变量
//根据当前线程thread获取到对应的ThreadLocal.ThreadLocalMap变量。
ThreadLocalMap map = getMap(t);
if (map != null)
//将sThreadLocal做为“key”,Looper实例做为“value”存储到ThreadLocal.ThreadLocalMap中
map.set(this, value);
else
//建立Map并存储值
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
//建立ThreadLocalMap,构造方法中传入第一次存储的键值对,并赋值到当前线程的threadLocals变量中。
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
复制代码
能够观察到,get()和set()方法获取当前线程中的ThreadLocal.ThreadLocalMap变量。再将Looper#sThreadLocal做为key,存储或获取对应的value,而value就是当前线程建立的Looper实例。
get()时是根据当前线程获取的Looper单例,再结合Looper#prepare(boolean),能够知道单个线程只会生成Looper单个实例。
问题1:Looper如何确保线程中只有一个单例。
回答:将Looper构造方法私有化。经过Looper的静态方法,确保只建立一次Looper对象,再将静态常量sThreadLocal做为key,Looper对象做为value,存储到当前线程的ThreadLocal.ThreadLocalMap变量中。
查看完Looper初始化的流程,再看看Looper#loop()的源码
#Looper.java
public static void loop() {
//获取当前线程的Looper
final Looper me = myLooper();
//若是Looper没有初始化,则抛异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//从Looper实例中获取当前线程的MessageQueue
final MessageQueue queue = me.mQueue;
//消息循环(经过for循环)
for (;;) {
//一、从消息队列中获取消息
Message msg = queue.next();
if (msg == null) {
//没有消息代表消息队列正在退出。
return;
}
//省略代码.....
//二、将Message发送给其标记的targetHandler
msg.target.dispatchMessage(msg);
//省略代码.....
//三、回收可继续使用的Message
msg.recycleUnchecked();
}
}
复制代码
Looper#loop()主要作3件事:
一、不断从MessageQueue中取出Message,若暂无Message,则无限等待。
二、将Message发送给目标Handler进行处理。
三、回收Message对象。
但发现有一种状况,当next获取到的Message为空时,则会退出Looper#loop()方法,即意味着消息循环结束。那何时MessageQueue#next()返回null?
#MessageQueue.java
Message next() {
//若是消息循环已经退出并处理掉,请返回此处。
//若是应用程序尝试在退出后从新启动looper,则可能会发生这种状况。
//即MessageQueue调用了quit()方法,再次调用Looper#looper()方法时。
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
//决定消息队列中消息出队的等待时间 or 标记为无限等待状态
int nextPollTimeoutMillis = 0;
for (;;) {
//.....
// nativePollOnce方法在native层方法。
//如果nextPollTimeoutMillis为-1,则无限等待,此时消息队列处于等待状态。
//如果nextPollTimeoutMillis为0,则无需等待当即返回。
//若nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),若是期间有程序唤醒会当即返回。
nativePollOnce(ptr, nextPollTimeoutMillis);
//尝试检索下一条消息。 若是找到则返回。
synchronized (this) {
//获取从开机到如今的毫秒数
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//获取MessageQueue中的顶层Message
Message msg = mMessages;
//.....
if (msg != null) {
//若是massage的时间大于当前时间
//Message的when = Handler发送Message1时的开机时间SystemClock.uptimeMillis() + Message自身的延迟时间
if (now < msg.when) {
// 下一条消息还没有就绪。 设置该Message的等待时间以在准备就绪时唤醒。
//将msg.when - now(当前开机时间) 获得该Message须要多久以后发送。
//则刷新nextPollTimeoutMillis的值,设置等待时间。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {//不然立刻发送Message
//只有当msg.target == null时,prevMsg才会赋值。
//听从Handler#obtainMessage()则通常不为空,此状况不考虑。
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
//刚开始时prevMsg为空
//则mMessages(顶层Message)指向当前顶层Message的下一个Message
mMessages = msg.next;
}
//将返回的Message的下一个Message引用置空。
msg.next = null;
msg.markInUse();
return msg;
}
} else {
//若是MessageQueue中没有Message,则会将nextPollTimeoutMillis重置为-1,继续等待
nextPollTimeoutMillis = -1;
}
//.....
}
//.....
}
}
复制代码
从源码开头得知,当MessageQueue退出时,MessageQueue#next()则会返回Message对象为空,从而关闭消息循环。
MessageQueue#next()主要进行等待操做和返回Message操做。而等待操做分两种状况:
一、MessageQueue队列中无Message,则进行无限等待操做。
二、当Message还没处处理时间时,则计算该Message还须要等待的时间,进行相应时间的延迟。
查看Handler如何处理Message:
#Handler.java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//若是Message的callback不为空,则将消息交由Message的callback处理
handleCallback(msg);
} else {
if (mCallback != null) {
//若是Handler的callback不为空,则将消息交由Handler的callback处理
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后才交由Handler的handleMessage()方法处理。
handleMessage(msg);
}
}
复制代码
Handler#dispatchMessage()主要做用时将Message分发处理。
当该Message对象的callback为空,目标Handler的callback也为空时,才轮到handleMessage()进行消息处理。
建立Message对象时,咱们通常会调用Handler#obtainMessage()获取Message对象,而不是直接new。先从Handler#obtainMessage()开始查看起因:
#Handler.java
public final Message obtainMessage(){
return Message.obtain(this);
}
复制代码复制代码
#Message.java
//Message链表,sPool是表头
private static Message sPool;
//记录当前链表中的数量
private static int sPoolSize = 0;
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
public static Message obtain() {
//加锁
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
//链表表头指向其下一个对象,即将表头从链表中取出
sPool = m.next;
//重置返回的Message的一些信息
m.next = null;
m.flags = 0; // clear in-use flag
//链表数量减一
sPoolSize--;
return m;
}
}
//若是链表表头为空,则new Message对象。
return new Message();
}
复制代码复制代码
Message#obtain(Handler)调用了重载方法Message#obtain()获取到Message对象并将Message的目标设置为调用Handler#obtainMessage()的Message。
Message对象中拥有一个Message类型的next对象,可经过next属性连成一个Message链表。Message中维系着一个静态Message链表,当链表不为空时,取出表头的Message进行返回,不然new一个Message对象。
以前查看Looper#loop()源码时获知,Looper#loop()最后会调用Message#recycleUnchecked(),将Message进行回收。
#Message.java
//Message链表最大存储数量值
private static final int MAX_POOL_SIZE = 50;
void recycleUnchecked() {
//将消息保留在循环对象池中时将其标记为正在使用。
//清除全部其余细节。
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
//加锁
synchronized (sPoolSync) {
//当前链表存储数量小于最大值,则继续回收
if (sPoolSize < MAX_POOL_SIZE) {
//next表明的是该须要回收的Message自身的next对象
//将自身的next指向原表头,
next = sPool;
//自身替换为表头,则经过表头的加减实现该Message链表的增长和删除。
sPool = this;
//链表存储数量加一
sPoolSize++;
}
}
}
复制代码复制代码
Message#recycleUnchecked()将Message的参数重置,并判断当前Messag链表存储的数量是否小于最大存储值,若小于最大存储值,则将该Message存储到链表中,重复使用。
Message经过对链表表头的增删操做来进行链表的增减。
问题2:为何建议使用Handler#obtainMessage()获取Message对象,而不是直接new。
回答:Message的回收机制实际上是享元设计模式的实现,Message对象存在须要反复、较大规模建立的状况,使用享元设计模式能够减小建立对象的数量,以减小内存占用和提升性能。
总结:
Message对象中拥有一个Message类型的next对象,可经过next属性连成一个Message链表。
Message类中维系着个静态Message链表,并标记其存储的数量值。
调用Handler#obtainMessage()或Message#obtain()方法时,尝试从该静态链表中获取循环再用的Message对象,不然new Message对象返回出去。
当Message被Handler处理完后,Looper对象会调用Message#recycleUnchecked()将Message进行回收,并存储到静态Message链表中。
咱们都知道,Handler能够经过sendMessage和post进行消息的发送,这两种方法到底有什么区别?先从sendMessage看起:
#Handler.java
public final boolean sendMessage(Message msg){
//发送一个0延迟的message
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
//延迟值不能小于0
if (delayMillis < 0) {
delayMillis = 0;
}
//将延迟的时间和开机时间相加
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//获取Handler建立时存储的当前线程的MessageQueue
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//将Message的目标TargetHandler设置为当前Handler
//若是经过Handler#obtainMessage()获取的Message早设置了TargetHandler为当前Handler,通常是新new的Message才为空。
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码复制代码
一路都是方法的嵌套,其中最关键的就是在传递给sendMessageAtTime()方法前,将延时时间和手机开机时间相加,获得Message对象的"执行时间"。
在继续查看MessageQueue#enqueueMessage():
#MessageQueue.java
//标记MessageQueue#next()的nativePollOnce()是否以 非零超时等待(无限等待)被阻止。
private boolean mBlocked;
boolean enqueueMessage(Message msg, long when) {
//.....
synchronized (this) {
//...
msg.markInUse();
//将延迟时间和开机时间相加获得的时间值存储到message的when变量中。
msg.when = when;
//获取链表表头的Message
Message p = mMessages;
boolean needWake;
//当表头为空时,或者本次发送的Message对象“执行时间”比表头的时间要小时
if (p == null || when == 0 || when < p.when) {
//将本次发送的Message存储到表头前面,将next属性指向原链表表头
msg.next = p;
//刷新MessageQueue中指向表头的变量
mMessages = msg;
needWake = mBlocked;
} else {
//一般不须要唤醒事件队列,除非队列的头部有屏障,而且消息是队列中最先的异步消息。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//开启循环,便利MessageQueue的Message链表
for (;;) {
//prev先指向原表头,后续循环中,不断指向下一个元素
prev = p;
//p指向下一个元素
p = p.next;
//若是p== null,表示到链表的尾部
//或者本次发送的Message对象的“执行时间”when比下一个元素的“执行时间”要短
if (p == null || when < p.when) {
//推出循环
break;
}
//...
}
//此时,prev指向的Message对象的when 比本次发送的Message对象msg的when小,即“执行时间”比它小。
//p可能为空,即链表尾;或者p指向的Message对象的when比 比本次发送的Message对象msg的when大,即“执行时间”比它大。
// 便可能存在 prev.when < msg.when <p.when 或 prev.when < msg.when
//将msg的next变量指向p所指的对象
msg.next = p;
//prev所指向的message对象的next变量指向msg
prev.next = msg;
}
//判断是否须要唤醒以前在MessageQueue#next()中“陷入沉睡”的nativePollOnce()方法。
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
复制代码复制代码
MessageQueue#enqueueMessage()主要做用是:
一、依据msg.when的大小,按从小到大的顺序,将msg插入到MessageQueue的Message链表中。
二、对于立刻执行的message,直接唤醒,中止nativePollOnce()的无限等待,让MessageQueue#next返回继续执行,从Message链表中取出Message,交由Looper对象进行处理。
模拟状况:
同时发送延迟400毫秒的Message对象 和 延迟300毫秒的Message对象;
100毫秒后,再发送延迟延迟250毫秒的Message对象;
情景分析:
同时发送两个分别延迟400和延迟300的Message对象,此时系统开机时间 time = SystemClock.uptimeMillis();
延迟400的Message对象:msg400, msg400 .when = time + 400;。
首先进入MessageQueue的Message链表,因为本来Message链表为空,p == null,表头mMessages指 msg400
延迟300的Message对象:msg300, msg300.when = time + 300;。
进入if(p == null || when == 0 || when < p.when)语句 ,p != null ,msg300.when < msg400.when , msg300.next 指向 msg400,链表表头指向msg300;
100毫秒后,发送延迟延迟250毫秒的Message对象。此时系统开机时间 time2 = SystemClock.uptimeMillis(),相对time 大了100毫秒,即time2 = time + 100毫秒。
延迟250的Message对象:msg250, msg250.when = time2 + 250, 即msg250.when = time + 350。
进入if(p == null || when == 0 || when < p.when)语句,语句不成立,进入遍历Message链表的for循环。when < p.when判断中,msg250.when > msg300.when,循环继续。msg250.when < msg400.when,跳出循环。执行msg.next = p; 和 prev.next = msg;两个语句,即msg250.next = msg400,msg300.next = msg250。
问题4:Looper如何管理Message队列(即前后发送不一样延迟时间的Message,Message队列如何排序)。
回答:Message经过SystemClock.uptimeMillis() + 延迟时间给自身when赋值,经过值的大小做为执行顺序。SystemClock.uptimeMillis() 不根据当前时区的时间变化而变化,只会因开关机而被重置,不然始终自增。
因此能够根据当前的SystemClock.uptimeMillis() 与Message对象的when对比,知道立刻执行仍是延迟多少秒后才执行。
转换到Handler#ost()的源码:
#Handler.java
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//若是Message的callback不为空,则将消息交由Message的callback处理
handleCallback(msg);
} else {
if (mCallback != null) {
//若是Handler的callback不为空,则将消息交由Handler的callback处理
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后才交由Handler的handleMessage()方法处理。
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
//只是调用callback的run()方法。
message.callback.run();
}
复制代码复制代码
post()传递的Runnable对象会被套上一层Message外壳,最后走和sendMessage()同样的路线。
Runnable对象将存储在Message对象的callback对象中。在Handler处理Message时,因为callback对象不为空,调用Handler#handleCallback()对Runnable对象调用run()方法,实现Message的处理。
问题3:Handler的sendMessage() 和 post()有什么区别。
回答:post()会将Runnable对象转换为Message对象,并把Runnable对象存储在Message对象的callback中,而后继续走sendMessage()的路线。
在Handler处理Message对象时,post()方法产生的Message对象中callback不为空,由Handler调用Runnable对象的run方法,不会调用handleMessage();
#Handler.java
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeCallbacks(Runnable r){
mQueue.removeMessages(this, r, null);
}
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacks(Runnable r, Object token){
mQueue.removeMessages(this, r, token);
}
复制代码复制代码
#MessageQueue.java
void removeMessages(Handler h, int what, Object object) {
//...
synchronized (this) {
//获取Message链表表头
Message p = mMessages;
//从头开始寻找,寻找第一个不符合条件的Message。分两种状况:
//一、链表表头直接不符合移除条件,即第一个不符合条件的Message为链表表头,推出循环。
//二、链表符合移除条件,将链表表头指向原表头的下一个Message,并回收原链表表头。新的链表表头继续进行判断,直到出现不符合移除条件的Message出现。
//最后链表表头mMessages 和 p都指向第一个不符合条件的Message,前面符合移除条件的Message已被移除。
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
//从第一个不符合条件的Message对象开始,迭代寻找其下一个Message是否符合移除条件。
while (p != null) {
Message n = p.next;
if (n != null) {
//判断是否符合移除条件
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
//获取p.next().next()的Message对象,即下下个对象。
Message nn = n.next;
//符合条件的回收
n.recycleUnchecked();
//将本来的下下个Message转移到next对象中,即转移到下一个Message的位置上。
p.next = nn;
continue;
}
}
//n == null,表示到链尾了,则 p == null,while循环结束。
p = n;
}
}
}
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
复制代码复制代码
removeMessages(Handler, int, Object) 根据Message中的what进行刷选移除对象。
removeMessages(Handler, Runnable,Object)则根据相同的Runnable对象进行刷选移除。
二者的都是走相同的移除对象流程,只是其中的一种刷选条件有所不一样,what针对的是Handler#sendMessage()发送的Message,Runnable针对的是Handler#post()发送的Message。
Handler#removeCallbacksAndMessages()则移除这两种刷选条件,针对全部Message。
问题5:removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什么
回答:removeCallbacks、removeMessages 和 removeCallbacksAndMessages 在待处理的Message链表中,根据各自的刷选条件寻找符合移除条件的对象,将符合条件的Message移除出Message链表,并回收该Message。