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

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

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

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

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

sendMessageAtTime内部调用了enqueueMessage

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

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

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

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

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

可以看到,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消息和正常消息怎么处理的啦

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值