Android Handler消息机制详解2

411 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

c.loop()

       Looper在通过prepare(x)后需要执行loop()来将消息进行循环处理;

public static void loop() {
    final Looper me = myLooper();
    //如果Looper为null,则抛出异常
    //主线程启动时会创建Looper,所以主线程创建多个Handler时,通过sThreadLocal.get()获取的是同一个Looper。
    //如果非主线程创建Handler,需要先执行Looper.prepare()来创建Looper,否则loop()时会抛异常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    //不断的循环取消息,如果没有消息则等待
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // message为空,说明调用了quit(),会return继而退出loop()
            return;
        }

        try {
            //处理消息
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        .......
        //消息处理完后释放
        msg.recycleUnchecked();
     }
}

       可以看到,在loop()内部会先通过myLooper()获取到对应线程的Looper,继而获取到对应的MessageQueue,接下来不断的去读取MessageQueue内部的消息,然后进行处理;

       没有消息时,会一直阻塞在Message msg = queue.next(),等待MessageQueue分发消息;

       有消息时,调用Handler来处理消息;

       消息处理完后进行recycleUnchecked()处理。

d.quitSafely()

       子线程在没有消息需要处理时,需要退出looper,否则一直block在loop()中的Message msg = queue.next();

public void quitSafely() {
    mQueue.quit(true);
}

      前面讲到,子线程的Looper是可以退出的,通过调用以上方法来退出,其实最终调用的MessageQueue的quit(),消息队列退出了,就没有消息进行处理了,Looper也就不需要轮询了,也就可以退出了。

2.Handler

a.Handler()

//默认主线程
public Handler() {
    this(null, false);
}
//使用线程已经创建好的Looper
public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Callback callback, boolean async) {
    ......
    //获取上面主线程创建的Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
    }
    //获取上面主线程Looper里面创建的MessageQueue
    mQueue = mLooper.mQueue;
    //默认为null,通过handler中的handleMessage来处理
    mCallback = callback;
    .......
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

       通过以上可以看到,在Handler的构造方法会分为几类:

       无参:代表默认使用当前线程的handler(一般是主线程),会通过Looper.myLooper()来获取到对应的Looper,如果Looper为null的话会抛异常,所以子线程使用Handler需要先通过Looper.prepare()来创建Looper;

       传入Looper参数:直接使用传入的Looper(使用HandlerThread时这样操作);

       从Looper中获取到对应的MessageQueue,Callback默认为null,通过实现的handleMessage()来处理。

       可以看到,在创建Handler时会通过myLooper()来获取到对应线程的Looper,此时两者建立了联系;

b.sendMessage()

       当调用Handler的sendMessagexx()发送消息时,最终都会调用到sendMessageAtTime(),内部就是将message加入到messagequeue中。

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    //获取MessgeQueue(即主线程的MessageQueue,上面已经创建完成)
    MessageQueue queue = mQueue;
    if (queue == null) {
        return false;
    }
    //将message加入队列
    return enqueueMessage(queue, msg, uptimeMillis);
}

      调用post(Runnable)也会将runnable转换为message:

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

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

      通过post(Runnable r)方式,最终也会转换为Message方式,将Runnable赋值给callback,有消息到来时,调用run方法来UI更新逻辑。

c.enqueueMessage()

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

       可以看到,在该方法内部主要执行了三件事:

       1.将Handler对象赋值给msg.target,从而message持有Handler对象的引用;

       2.如果mAsynchronous为true,会执行setAsynchronous(true)将其设置为异步消息,跟消息屏障一起使用,处理优先级高的消息(UI绘制);

       3.调用MessageQueue内的enqueueMessage()最终把发送的Message放进了主线程的MessageQueue里面进行循环;