Handler消息机制 源码解读

基本概念

Handler消息机制的作用

大家知道子线程没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException,为了让子线程能间接操作UI界面,Android中引入了Handler消息传递机制,通过Handler切换到主线程进行UI操作。

Handler、Looper、MessageQueue、Message的关系是什么?

  • Handler用于发送和处理消息。而发出的Message经过一系列的周转后,最终会传递回Handler中,最后更新UI。

  • Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之前交换数据。

  • MessageQueue是消息队列,用于存放Message。Message在消息队列中,等待Looper取出。每个线程中只会有一个MessageQueue对象。

  • Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入一个无限循环中,每当MessageQueue中存在一个Message,Looper对象就会将其取出,传递到Handler中进行处理。每个线程中只会有一个Looper对象。

Handler消息机制疑问

从上面的基本概念中,我们不难会产生疑问,比如:

  • 在Message的周转过程中,是怎么切换到主线程的?
  • 如果当前线程中new了多个Handler,它们发送消息后会错乱吗?会不会找错Handler对象。
  • Handler的post方法和sendMessage有什么区别?
  • 怎么保证每个线程中只能存在一个Looper和MessageQueue?
  • 子线程为什么不能直接new Handler?
  • 主线程为什么不用手动创建Looper?
  • 主线程中的Looper无限循环,为什么没有造成ANR?

下面,我将从源码角度,对以上疑问进行探索。看完本篇博客,相信你心里就会有答案了。

初识API

Message

我们先来简单认识一下Message

    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;

上面几个的用法,大家都知道,就不用介绍了。我们来看看下面的。

    Handler target;
    Runnable callback;

Message中可以保存Handler对象,也可以保存Runnable,具体用法看完本篇博客就知道了。
还记得Message.obtain用法吗?

 public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; 
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

因为Message被处理完过后,是不会直接回收的,默认会保存一定数量的Message以供复用。我们可以使用Message.obtain复用,以免创建多余的Message。

MessageQueue

MessageQueue是什么?我们可以给它理解成一个集合,比如List,我们可以添加消息,也可以读取消息,移除消息。当然MessageQueue的内部是通过一个单链表的数据结构来实现的,理解起来可能有点费劲,我们只需知道有两个重要的方法enqueueMessage插入消息,next取出消息。

  //======================插入消息=================================
    boolean enqueueMessage(Message msg, long when) {
            //...
            //省略了部分代码
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p =
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值