Handler、Looper、Message源码学习总结

一、Handler、Looper、Message三者作用和关系

1、Message

概念:线程中一个个需要处理的任务称为消息,存放任务的是一个队列,成为消息队列(MessageQueue),内部存储结构为单链表。消息是Message类的实例,他有很多个属性,其中有三个需要自己定义:

what:用来标识一条消息

obj:由用户指定,随消息发送的对象。

target:一般指处理消息的Handler

2、Looper

概念:Looper与一个线程绑定,保证线程只有一个Looper对象,Looper只有一个消息对列(MessageQueue)。

主要方法:

prepare()方法主要是初始化一个Looper对象并存储在当前线程中(ThreadLocal),因此该方法只调用一次,否则会抛出异常;

loop()方法是一个阻塞方法,即一个无限循环,他不断地从MessageQueue中取消息,交给message的target的dispatchMessage()处理;如果MessageQueue为null,则一直等待下去。

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;
 
        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
 
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
 
            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
 
            msg.target.dispatchMessage(msg);
 
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
 
            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
 
            msg.recycle();
        }
}

3、Handler

概念:Handler的工作主要包含消息的发送和处理过程。消息的发送主要有两种方式:

主要方法:

sendMessage()方法:通过该方法,辗转反则最后获取MessageQueue然后调用了enqueueMessage()方法向消息队列中插入一条消息,MessageQueue的Looper收到消息后回调Message的target的dispatchMessage方法。

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);
    }


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


post(new Runnable())方法:该方法将Runnable对象封装Message(将Runnable对象赋值给msg的callback属性),接着与sendMessage()方法后续一样,调用send的一系列方法将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;
    }

总结:

通过上面的描述可以发现,Android的异步消息处理机制其实就是Handler对消息的发送和处理过程。两种发送方法最终都是将Message添加到MessageQueue(消息对列)中,再由Looper轮询消息队列将消息发送给对应的target处理。那么还牵扯到两个问题:(1)Handler是怎么与MessageQueue建立联系的,即Handler如何获取当前MessageQueue?(2)两种不同的方式发送后,具体的处理过程是怎样的?

二、Handler如何获取当前线程的Looper呢?

在使用Handler之前,我们都是初始化一个Handler实例,在Handler的构造函数中会通过Looper.myLooper()获取当前线程的Looper实例,并通过该实例获取MessageQueue,从而建立了Handler与MessageQueue的联系。这也解释了为什么在线程开始处理任务前必须先调用getLooper()获取Looper对象。(主线程自动初始化Looper,因此不需要手动操作)

Handler、Looper、Message源码学习总结

三、Handler获取消息后具体的处理过程

前面讲到Looper.loop()方法不断轮询消息队列,只要有Message就通过msg.target.dispatchMessage()方法,将消息传递给相应的target处理。所以我们需要去找dispatchMessage()这个方法的具体实现:

Handler、Looper、Message源码学习总结

结合前面提到的Handler两种发送方式,

1、当用post(new Runnable())方式时,事实上是将Runnable封装为Message的callback属性,在处理时调用handleCallback(),进而调用run()方法,如下:

private static void handleCallback(Message msg){
    msg.callback.run();
}

2、当用sendMessage()方法时,msg.callback就为null,所以检查mCallback是否为空,未定义时mCallback为null,所以最后调用handleMessage()方法进行具体的处理。

mCallback不为null就调用mCallback的handleMessage()方法。Callback是个接口,定义如下:

public interface Callback{
    public boolean handleMessage(Message msg);
}

这种方式是告诉我们,通过Callback可以采用如下方式来创建Handler对象:Handler handler = new Handler(callback),这种方式不需要派生Handler子类。

总结:

1、Looper.prepare()在本线程保存一个Looper实例,然后该实例保存一个MessageQueue对象,因为MessageQueue在一个线程只存在一个,因此Looper.prepare()方法只调用一次。

2、Looper.loop()通过一个无限循环,不停地轮询MessageQueue,只要有消息到来,就通过回调msg.target.dispatchMessage()方法将消息传递给对应的target;当MessageQueue为null,就一直等待下去。

3、Handler的构造方法会获取当前线程保存的Looper实例,进而与Looper实例中的MessageQueue相关联。

4、Handler的sendMessage()方法,会给msg的target赋值为handler本身,然后加入MessageQueue中;post(new Runnable())方法会给msg的callback赋值为Runnable,然后加入MessageQueue。

5、在构造Handler实例时,我们要么重写handlerMessage()方法,要么重写run()方法,也就是msg.target.diapatchMessage()最终调用的方法。

参考文章:

https://blog.****.net/lmj623565791/article/details/38377229/

https://www.jianshu.com/p/8ecacbb97af4