Handler消息追踪和源码解析

Handler主要用于异步消息的处理,当发出一个消息,消息进入消息队列,looper进行轮询处理消息,也就是发送消息和接收消息不是同步的处理。

Handler机制的五个相关类

  1. Handler主要用于发送消息和最终处理消息。
  2. Message具体的消息,用于携带信息,同时用于构建链表
  3. MessageQueue消息队列,存储消息,对消息按照时间顺序排序
  4. Looper阻塞式从消息队列取出消息
  5. ThreadLocal线程共享变量,存放每个线程对应的looper

下面来追踪一个消息从发送到最终处理是如何进行的

//发送消息有以下九种方式
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable,long)
sendEmptyMessage(int)
sendEmptyMessageAtTime(int)
sendEmptyMessageDelayed(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

前面六种都会在Handler里面生成一个message,然后对消息的时间加以处理,最终加入消息队列,下面以post为例:

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

其中getPostMessage方法中生成一个Message,并把Runnable对象赋值给Message中的callback,并返回message

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

消息最终要加入消息队列,队列里面排序是按照时间顺序,现在来看看是怎么对时间进行处理的,我们发送消息是可以发送延时消息的,用的方法就是sendMessageDelayed,下面是源码:

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    //如果传递过来的时间小于0,默认延时0毫秒
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    //uptimeMillis是系统开机时间到现在的时间,这个时间是无法更改的,所以能准确的进行排序
    return sendMessageAtTime(msg,SystemClock.uptimeMillis() + delayMillis);
}

下面来看看sendMessageAtTime方法:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    //消息队列,创建的Handler的时候获取并赋值的,创建Looper的时候创建的,在looper中有消息队列的引用
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
        this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

mQueue是怎么来的呢,消息队列都是随着Looper创建的,创建Looper使用的是Looper.prepare(),并存入ThreadLocal中,同一个线程共享一个,主线程的looper在ActivityThread中创建,在Looper类中长期持有主线程的looper

public static void prepare() {
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //存入ThreadLocal
    sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
    //构造,创建的时候也创建了一个消息队列
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

Handler在创建的时候就会获取到当前线程的Looper和消息队列

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
        (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
            klass.getCanonicalName());
        }
    }
    //根据当前线程在ThreadLocal中获取对应Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
    }
    //获取消息队列
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

现在消息队列也有了,时间也进行了处理,该去加入消息队列了

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    //让Message持有Handler的引用,因为Handler才是最终处理消息的,轮询消息的时候直接msg.target.dispatchMessage(msg)进行处理
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

比较时间加入消息队列

boolean enqueueMessage(Message msg, long when) {

    ......

    synchronized (this) {
        ......
        msg.markInUse();
        //设置消息的时间
        msg.when = when;
        //mMessages是消息队列排在最前面的消息
        Message p = mMessages;
        boolean needWake;
        //消息队列为空,或者新加入的消息时间为0,或者新加入的时间小于排在最前面的时间的时候,新加入的消息将排在最前面
        if (p == null || when == 0 || when < p.when) {
            //消息列表是一个单向链表,当前消息持有下一个消息的引用,可以根据当前消息找到后面的任意一个消息
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {

            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //当新消息排不到最前面时候,从最前面消息开始一个一个对消息时间进行比较
            for (;;) {
                prev = p;
                p = p.next;
                //p为prev的下一个消息,当比较到最后一个且最后一个消息为空时候,或者新消息时间小于消息p的时间,跳出循环
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            //将新消息插入链表,前一个消息prev的next就是新消息,新消息的下一个就是p
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    //插入消息队列成功,返回true
    return true;
}

Looper的loop方法是阻塞式轮询消息,msg.target.dispatchMessage(msg)最终处理消息

public static void loop() {
    //获取当前线程的looper
    final Looper me = myLooper();

    final MessageQueue queue = me.mQueue;

    for (;;) {
        //从消息队列里面取消息时间小于当前时间的消息
        Message msg = queue.next(); // might block

        ......

        try {
        //最终的消息处理target是一个Hanler
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        msg.recycleUnchecked();
    }
}

回到Handler最终处理消息

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //这是用post方式传入Runnable处理消息方法
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //这是创建Handler传入了Callback处理消息方法
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //这是Handler的匿名方式创建处理消息的方法
        handleMessage(msg);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值