探究Handler的postAtFrontOfQueue方法

目录

一、插曲

二、优化

三、继续深入,锁?

总结



一、插曲

最近项目中遇到一个问题:

在某个子线程的回调中,用handler(主线程中创建的)post去更新了一个UI,类似下面的样例代码:

Handler mHandler = new Handler(Looper.getMainLooper());
// onPageLoad在子线程中调用
public void onPageLoad(){
    Log.d("bcc", "onPageLoad1: "+System.currentTimeMillis());
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            Log.d("bcc", "onPageLoad2: "+System.currentTimeMillis());
            // 下面是刷新view的代码
                .....
        }
    });
}

结果发现:从onPageLoad1到onPageLoad2间隔了好有5~6秒。

于是很快分析出了原因:在我们app的首页刚进来,绘制任务比较重,主线程的looper比较繁忙时,确实会发生这样的情况。

如何优化?

二、优化

经过一顿xxx,发现了handler还有一个这样的api

 尼玛 一堆英文注释!!

重点

Causes the Runnable r to executed on the next iteration through the message queue

意思就是:looper下一次拿到的消息用着这个方法post过去的

嘿嘿!如果用这个岂不是很快就执行了呢?算了还是继续跟一下源码吧,万一理解错了。

handler.java:

这个enqueueMessage中的第三个参数uptimeMillis 为0,读者们需要重点关注一下,下文分析要提到。

MessageQueue.java:

             

 好嘛!还挺长。。。最终调用到MessageQueue中的enqueueMessage方法。

还记得上文提到了uptimeMillis 吗?值为0,也就是这里的when,显然会执行下面逻辑:

//

if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
}

///

消息队列其实就是一个单向链表,p就是当前链表的头部(c里面就是链表头部指针),上面的这段逻辑就是把新来的消息插入了链表的头部,也就是消息队里的头部。

哈,果然是这样。于是换成postAtFrontOfQueue后,效果果然明显,间隔只有200多ms了。

等等?还有200ms?这样又是什么原因呢?

三、继续深入,锁?

理论上新的消息被添加队列头部(不考虑后面又有新的消息被添加到头部),当正在执行的任务完成后,新的消息很快会被执行。带着上面的疑惑,我们再回过头看一下MessageQueue#enqueueMessage的源码:

 原来这里有个锁,锁住是当前looper中的消息队里,也就是主线程的消息队里,可想而知主线程的消息对列一般是很“忙”的,而我们是在子线程中调用了postAtFrontOfQueue,大概率子线是无法竞争过主线程的,因此消息被添加到消息队列头部是有一定的延迟的。

ok,到此分析完结。


总结

1、如果想要加快handler对某个特定任务的执行,可以采用postAtFrontOfQueue方法。

2、如果在子线程或者优先级比较低的线程中使用postAtFrontOfQueue,那就要考虑到postAtFrontOfQueue还是会出现一定的“延迟”。所以想要达到立即执行的效果,不能跨线程使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值