handler消息和delay消息的工作机制

做Android开发的同学,应该都用过hanlder,具体的场景比如:在一个子线程中,做耗时操作,然后通过handler.sendMesssage发送消息到主线程,更新ui,有时也通过handler.sendMessageDelay,发送一条延时消息,那有没有思考过sendMesssage和sendMessageDelay内部是如何处理消息的?假设发送一条延时消息,马上发送一条正常消息,延时消息会阻塞正常消息吗,有经验的同学可能会知道,不会阻塞,那为什么呢?今天我们就来看看这个问题

看本文需要事先对handler的工作原理有个大概认识,熟悉MessageQueue,Looper,Message

handler的一系列send和post,最后都会调用handler.sendMessageDelayed

handler消息和delay消息的工作机制_第1张图片

sendmessageDelayed里面只是简单处理了delayMillis,这里一个比较重要的参数时uptimeMillis,这里传入的是当前时间+delay时间

handler消息和delay消息的工作机制_第2张图片

sendMessageAtTime内部调用了enqueueMessage

handler消息和delay消息的工作机制_第3张图片

把当前handler对象,赋值给了msg.target,最后调用了queue.enqueueMessage,这个方法比较长,我们摘取重要的

handler消息和delay消息的工作机制_第4张图片

message是一种单链表解构,mMessage会指向链表的第一个元素,链表中的元素以时间,从小到大排序

nativeWake这个方法很重要,它是实现唤醒的关键,needWake的赋值我们只看mBlocked,这个mBlocked我们后面讲

我们知道消息的处理是在Looper.loop中进行的,一个死循环,不断从messageQueue中获取消息,如果得到消息,那么交给对应的handler进行处理

messageQueue中获取消息是通过messageQueue的next方法,代码很长,我们精简一下

handler消息和delay消息的工作机制_第5张图片

可以看到,next方法也是一个死循环,循环开始会调用nativePollOnce,传入nextPollTimeoutMillis,

如果nextPollTimeoutMillis=0,这个方法会立刻返回,不会阻塞

如果nextPollTimeoutMillis=-1,会一直阻塞,直到被唤醒,再返回

如果nextPollTimeoutMillis=某个正值,会一直等到timeout,返回,或者被唤醒,返回

如果nativePollOnce有返回之后,next就能返回一个message给Looper啦,现在的问题是nativePollOnce在什么时候有返回

知道这点之后,我们接着看next的实现 

我们在方法底部,找到了mBlocked赋值为true,前边在enqueMessage中,我们有所提到,它是决定延时是否唤醒的关键

假设一种情况,我们创建一个主线程的handler,然后发送一个延时消息,再发送一个正常消息,这个时候MessageQueue的enqueMessage和next是怎么处理的呢?

回到enqueMessage的实现,发送延时消息时,由于消息队列中没有消息,所以p为null,mMessage指向当前消息,needWake被赋值为mBlocked,前面分析可以知道,如果这时候mBlocked为true,那么接着会执行nativeWake,接着nativePollOnce返回,然后去处理这个消息,这个mBlocked是true吗?

回答这个问题,我们需要回到next方法,看mBlocked唯一被赋值为true的地方,假设上一条消息全部处理完,也就是next方法返回了一个message给Looper.loop,Looper处理完这个消息以后,再次循环调用MessageQueue的next方法,这时候的nextPollTimeoutMillis为0,nativePollOnce会立刻返回,接着如果此时没有消息啦,那么nextPollTimeoutMillis被赋值为-1,mBlocked赋值为true,再次循环时,next方法进入阻塞状态

这里可以得出结论,mBlocked为true,进入阻塞,等待下次唤醒

这里我们就知道了,原来当我们发送delay消息的时候,mBlock为true,也就是nativeWake会被调用,next中nativePollOnce得已返回,然后处理这个delay消息,如何处理的呢

这时候msg!=null,nextPollTimeoutMillis赋值为当前时间和设置delay的when时间之间的差值,接着mBlocked赋值为true,下次循环进入阻塞状态

如果这时候,我们发送一条正常消息,由于消息队列中已经有了一条延时消息,那么这条消息会被插入到队列的第一个元素,然后调用nativeWake唤醒,next方法得以继续执行,nativePollOnce返回,去处理队列中的第一个元素,也就是我们发送的一条正常消息,处理完毕返回一个message给Looper,同时从队列里边删除该元素,Looper处理完消息,接着调用MessageQueue的next方法,去重新计算delay的时间

好啦,到这里,我们应该比较清楚delay消息和正常消息怎么处理的啦

 

 

 

你可能感兴趣的:(安卓源码)