Android开发之十六:Message、MessageQueue、Looper、Handler原理知识点源码分析

概述

handler作为android消息处理的重要机制,全面回顾下其涉及的知识点。

关键类

整个消息处理机制中涉及到的主要类有: 
Message : 负责消息封装 
MessageQueue : 负责将消息封装为消息队列 
Looper : 负责从消息队列中获取消息并分发 
Handler : 负责消息发送及处理

Message

看看代码中的类注释:

定义包含描述和任意数据对象的消息,发送到Handler。 该对象包含两个额外的int字段和一个额外的对象字段,允许您在很多情形下不用分配新的对象。 
虽然Message的构造函数是公共的,但最好的方法是是调用Message.obtain()或其Handler.obtainMessage()方法,从缓存池中获取一个Message对象。

讲的还是比较清楚,Mesasge的职责就是包装数据,缓存和生成Message。 
那么来看看Message对象中的关键字段和方法:

public final class Message implements Parcelable {

    //在handler处理消息时,用于区分消息内容
    public int what;
    //可携带int参数
    public int arg1; 
    //可携带int参数
    public int arg2;
    //包装的消息对象
    public Object obj;

    //缓存池对象
    private static Message sPool;
    Message next;
    private static int sPoolSize = 0;
    //缓存池的大小
    private static final int MAX_POOL_SIZE = 50;

     //从全局的缓存池中获取一个新的Mesasge实例,避免分配新的对象
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    //Message本身携带了target对象,也就是目标handler
    //因此消息可以通过target进行发送
    public void sendToTarget() {
        target.sendMessage(this);
    }
//message对象的回收缓存
void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}


sPool是一个链表结构,在obtain()方法中,sPool为空的话将直接返回一个新的Message对象,如果不为空,那么就取当前对象返回,注意该方法使用synchronized进行代码块同步。 
Message当中还存在其他的一些方法,基本都是用来辅助Message的构建和缓存的,这里不在列出了。

MessageQueue

看看代码中的类注释:

低级别类,包含要由Looper调度的消息列表。 消息不会直接添加到MessageQueue, 而是通过与Looper相关联的Handler对象。 
您可以使用Looper.myQueue()检索当前线程的MessageQueue 。

由Looper类来进行调度,Message是由Handler对象处理才能放入MessageQueue中。 
其中关键的字段和方法:

public final class MessageQueue {
    Message mMessages;
    //将Mesage入队
    boolean enqueueMessage(Message msg, long when) {

            //...省略代码
                Message p = mMessages;
             //...省略代码

            if (p == null || when == 0 || when < p.when) {
                //mMessages是空的,或者如果新msg的执行时间为0,或者小于当前mMessages的时间
                //那么msg会成为链表的新头部
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    //一直找到队尾或者执行时间小于找到的message的时间
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //然后把新的msg插入进去
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            //...省略代码
          }
    }
//获取Message
Message next() {
    //...省略代码
    Message prevMsg = null;
    Message msg = mMessages;
    //...省略代码
      for (;;) {
        if (prevMsg != null) {
           prevMsg.next = msg.next;
       } else {
           mMessages = msg.next;
       }
       msg.next = null;
       if (DEBUG) Log.v(TAG, "Returning message: " + msg);
       msg.markInUse();
       return msg;
    }
}


总的来说Looper负责消息的入队和出队,主要根据Message的执行时间来确定Message在链表中的位置,时间越小,在队列的中的位置就越靠前,被Handler执行的就越早。

Looper

类注释:

用于为线程运行消息循环的类。 默认情况下线程 没有与之关联的消息循环; 调用prepare方法来创建一个Looper对象来运行循环的线程中,然后调用loop方法让它处理消息,直到循环停止。 
大多数与消息循环的交互都会通过Handler对象。

意思就是我们可以通过Looper.prepare()方法来获取一个当前线程的Looper对象。 
其中关键的字段和方法:

public final class Looper {
    //当前线程的ThreadLocal,保存了Looper对象  
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    //application 的主Looper对象,负责整个App的消息处理
    private static Looper sMainLooper;  // guarded by Looper.class
    //消息队列
    final MessageQueue mQueue;

//准备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来给当前线程设置一个Looper对象
        sThreadLocal.set(new Looper(quitAllowed));
    }

    //Application 的主Looper对象,在ActivityThread这个类中调用该方法来生成Looper
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
}
//获取Application的主Looper对象
 public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    //获取当前线程的Looper对象
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    //获取当前线程的MessageQueue对象
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }
//从MessageQueue 中取出Message进行分发处理
 public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        //...省略代码

        for (;;) {
        //获取Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

         //...省略代码
            try {
            //使用Message包含的Handler对象进行消息的处理
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {

            }

        //...省略代码
            //回收message
            msg.recycleUnchecked();
        }
    }



从上面可以看出Looper对象的主要责任一个是生成整个Applicaion的主Looper对象,运行在UI线程,这一步是在ActivityThread的main()方法中调用的,如果是在子线程的话也可以生成不同的Looper对象,这样各个线程有属于自己的Looper对象,消息的处理互相不受影响。 
另外就是从MessageQueue中取出Message发送到对应的Handler对象进行处理。 
对于ThreadLocal类的一些分析:Android ThreadLocal及InheritableThreadLocal分析。

Handler

Handler中的关键注释:

Handler有两个主要用途:
(1)安排消息和 runnables将在未来某个点执行; 
(2)在与您自己不同的线程上执行执行消息入队;

其中关键的字段和方法:

public class Handler {

    //通常我们调用该方法来发送消息
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//该方法可以设置消息执行的延迟时间
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
//该方法可以设置消息在指定的时间点运行
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        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);
    }
//最终消息进入MessageQueue的队列
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
     //这里就将handler的引用传递个message对象了
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
//可以进行Runnable任务
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    //将Runnable任务封装成Message
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
    //处理消息,注意msg.callback和mCallback 的特殊情况,尤其是传入了
    //mCallback 的情况下将不会走handleMessage()方法
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

    //子类必须实现该方法来处理消息
    public void handleMessage(Message msg) {  }
}


总结

消息处理的整个执行流程:

Handler.sendMesasge();
Handler.sendMessageDelayed();
Handler.sendMessageAtTime();
Handler.enqueueMessage(),至此消息入队了;
Looper.loop()从MessageQueue中取出消息,分发给目标Handler;
Handler.handleMessage()
当然中间的一些特殊流程及处理要注意。

发布了377 篇原创文章 · 获赞 145 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/Windgs_YF/article/details/104293104