Handler 在子线程中遇到的问题

Handler 的源码在前面几章分析过,一般也被用于切换线程,刷新UI使用。也被用来做延迟处理事件,一般都是在主线程中使用。

根据业务逻辑,开启了子线程,在其中做耗时操作,同时设置了一个超时时间,如果超过了这个时间,则终止操作,进行下一步逻辑。 这是一个很简单的需求,但由于笔误,造成了一个bug,原因在于Handler的延时操作不是在主线程中执行,而是在子线程中,见代码

    Handler mHandler;
    
    void test(){
        HandlerThread handlerThread = new HandlerThread("test", -20);
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper(), callback);
        mHandler.sendEmptyMessage(0);
    }    

    Handler.Callback callback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if(msg.what == 1){
                Log.e("TAG",  "  handler  time out "  );
            } else if(msg.what == 0){
                mHandler.sendEmptyMessageDelayed(1, 5000);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.removeMessages(1);
                Log.e("TAG",  "  thread  "  );
            }
            return false;
        }
    };

就是这么个代码,写出了个bug,固定延迟5秒执行超时操作,子线程耗时2秒,实际业务中是不确定的,有可能大于5秒,也有可能小于5秒,所以就导致bug是偶现的:子线程网络请求,超过了5秒,但没执行相应的超时回调。刚开始没注意到这个bug,后来仔细看了看代码,才发现原因所在。

 
HandlerThread 是个子线程,新建的 Handler 使用了子线程对应的 Looper,说明此Handler是在子线程中执行的;此刻,如果子线程被阻塞了,比如阻塞了7秒,那么Handler也会等7秒然后才检查自身对应的 MessageQueue 中是否有Message需要执行,这也是为什么5秒的时候没有触发延迟消息的原因。如果子线程阻塞了2秒,Handler本身的延迟的是5秒,此刻是没影响的,由于执行了 mHandler.removeMessages(1); 会把消息移除掉,如果没有这行代码,Handler 是会执行延迟发送的消息。

这个好像与平常印象中的Handler不一样啊!印象中只要Handler做了延迟消息发送,只要不取消,它会在指定的时间点执行,为什么在子线程中失效了?其实不是失效了,有这种印象只是说明对Handler的原理还不是很清楚。Handler 中的队列 MessageQueue 存储消息,而 Looper 中则不停的抽取消息,MessageQueue对外提供消息,此时如果有到时间的消息,则提供给外部;如果最近的消息还需要时间等待,则会进入睡眠状态,等待一段时间后被唤醒,执行对外提供消息功能,睡眠的时间则是头部消息还需要等待的时间;子线程中,由于被阻塞了,Looper根本来不及抽取消息,所以等阻塞消失后,才有消息发送出来,外部才接受到消息。


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值