Handler、MessageQueue、Looper和Thread原理简析

 1.Handler官方介绍

    一个Handler允许您发送和处理与线程的MessageQueue相关联的消息和Runnable对象。每个Handler对象都与一个线程和该线程的消息队列相关联。当您创建一个新的Handler时,它将绑定到正在创建Handler对象的线程/消息队列——从那时开始,它将向该消息队列传递消息和runnables,并将它们(消息和runnables)从消息队列中取出时执行它们。

    Handler有两个主要用途:(1)将消息(Message)和runnables在将来的某个时间点执行;(2)在不同的线程上执行要执行的操作。

 调度消息是通过post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,Object,long)、sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)和sendMessageDelayed(Message,long)方法完成的。post版本允许您在接收到的消息队列(Message)中对Runnable对象进行调用;sendMessage版本允许您对包含包数据(a bundle data)消息(Message)由Handler的handleMessage(Message)方法处理(要求您实现Handler的子类)。

    在投递或发送消息给到Handler时,您可以允许在消息队列准备就绪时立即处理该内容,或者延迟处理或者指定时间处理。后两种方法允许您实现超时、计时和其他基于时间的行为。

    当为应用程序创建一个进程时,它的主线程将用于运行一个消息队列,该队列负责管理顶级应用程序对象(活动-activities、广播接收器-broadcastReceiver等)以及它们创建的任何窗口。您可以创建自己的线程,并通过Handler与主应用程序线程进行通信。这是通过调用post或sendMessage方法来完成的线程间的通信。然后,给定的Runnable或消息将被安排在Handler的消息队列中,并在适当的时候进行处理。

参考官网:https://developer.android.google.cn/reference/android/os/Handler

2.Handler原理

2.1.首先要了解Handler是什么,及用途

参见:1.Handler官方介绍

2.2.了解Handler涉及的相关类(Handler,Message,MessageQueue,Looper,Thread)

2.2.1.Handler相关类基础关联说明

Handler使开发人员可以参与到Android的线程中消息循环的机制,开发过程中大多数情况下我们使用Handler和Message就可以满足大部分开发要求,Message是Handler对开发人员暴露经常使用的类,Message也可以理解为是一种载体,通过载体只是把信息从A线程传给B线程;作为程序员,总是会好奇背后的一些东西,Handler机制又是如何实现的,Handler设计Thread、MessageQueue和Looper这几个类之间的关系是什么?

Handler、MessageQueue、Looper和Thread原理简析_第1张图片

通过上面的图,可以看到Thread使用整个Handler机制的基础,即Looper和MessageQueue构建在Thread之上,Handler构建在Looper和MessageQueue之上,在调用Handler的时候间接是在调用偏低层的类来完成相应的任务;

2.2.2.MessageQueue(消息队列)

Thread时Handler机制的基础,每个线程(Thread)维护一个消息队列---MessageQueue。

为什么会有消息队列呢?例如我们有多个后台下载文件的线程,当多个后台下载文件的线程同时下载完成时,需要通知前台下载完成的通知,因为线程某一个时刻只能处理一件事情,那么应该先显示哪个通知,这也就引入消息的队列的概念,我们将每个下载完成的通知存放到Message中,然后加入到消息队列中;Thread会依次取出消息队列中的Message,然后依次进行处理;Message可以理解为线程要处理的一件事件,MessageQueue理解成线程要处理的Message的池子;

MessageQueue既然是一个队列,那么一定会提供入队列和出队列的方法,入队列方法:boolean enqueueMessage(Message msg, long when) ,出队列方法:Message next();enqueueMessage方法负责发消息放入消息队列,next方法负责从消息队列中取Message;

2.2.3.Looper

上面说完了MssageQueue消息队列,那么是什么让消息队列运转起来的,那就是Looper了,那么Looper如何让怎么实现的呢?

Looper类在线程中使用消息循环方式让MessageQueue运转起来的,当我们创建线程时默认不会创建线程对应的消息队列,需要开发人员调用Looper.prepare()方法,然后调用Looper.loop()方法;典型的Looper线程的示例,伴随着Looper使用preapre()方法和loop()方法去创建一个通信的Hander。

  class LooperThread extends Thread {
      public Handler mHandler;
       public void run() {
           Looper.prepare();
  
           mHandler = new Handler() {
               public void handleMessage(Message msg) {
                  // process incoming messages here
               }
           };
  
           Looper.loop();
       }
    }

preapre方法和loop方法需要在run方法中调用,通过查看源代码

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

查看到Looper构造方法是私有的构造方法,外部是不允许新建Looper对象的,也间接说明Looper和线程是一对一的关系;只能通过Looper.myLooper()方法获取当前线程所绑定的Looper;

Looper.prepare()方法介绍

// sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal sThreadLocal = new ThreadLocal();
/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

prepare方法主要负责准备工作,只能准备工作完成以后才可以调用loop()方法,那么都做了哪些准备工作呢?

调用sThreadLocal.get()首先判断线程是否已经绑定了Looper,若绑定了则会抛出运行时RuntimeException异常,说明一个线程不能绑定多个Looper,接着调用new Looper(quitAllowed)新建Looper对象,然后通过sThreadLocal.set(new Looper(quitAllowed));方法建立Looper与线程的绑定关系,通过sThreadLocal.set方法建立Looper和sThreadLocal绑定;

这样就完成了线程sThreadLocal与Looper的双向绑定: 
a. 在Looper内通过sThreadLocal可以获取Looper所绑定的线程; 
b.线程sThreadLocal通过sThreadLocal.get()方法可以获取该线程所绑定的Looper对象。

通过Looper构造函数也可以了解到Looper和MessageQueue是如何关联上的:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

通过构造函数代码可以看到在Looper构造函数中新建了一个,MessageQueue对象同时赋值给mQueue对象,即建立Looper和MessageQueue的关联;

注意事项:Looper.prepare()方法只能调用一次,若调用多次会导致运行时异常;

调用完成prepare方法以后,做完准备工作,再已经建立相互绑定的线程中就可以调用loop()方法了,那么loop方法中都做了什么呢?

loop方法代码如下:

 /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            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.recycleUnchecked();
        }
    }

下面标是loop方法执行的关键点:

a. final MessageQueue queue = me.mQueue;

调用myLooper获取当前线程绑定的Looper,然后获取Looper中的mQueue消息队列;

b.for(;;)

没有设置条件,死循环;

c. Message msg = queue.next(); 

我们通过消息队列MessageQueue的next方法从消息队列中取出一条消息,如果此时消息队列中有Message,那么next方法会立即返回该Message,如果此时消息队列中没有Message,那么next方法就会阻塞式地等待获取Message。 

d.msg.target.dispatchMessage(msg);

将消息派发给关联的Handler进行处理,target指关联处理消息的Handler

2.2.3Handler

Handler是最顶层的一个类,是构建在Thread,MessageqQueue,Looper之上的;

Handler具有多个构造函数如下:

a. publicHandler() 
b. publicHandler(Callback callback) 
c. publicHandler(Looper looper) 
d. publicHandler(Looper looper, Callback callback) 

a和b构造函数没有传入Looper,通过Looper.myLooper();方法获取当前线程绑定的Looper;

c和d方法可以传入Looper对象,保存在mLooper对象中;

b和d的方法中Callback是处理消息的另一种方式,可以实现Callback接口,重新handleMessage方法;

/**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     *
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

如果构造方法中没有传入Callback则需要重写Handler类中的handleMessage方法,传入则使用Callback中的handleMessage方法处理Message;类似于new Thread()使用Thread中的run方法和new Thread(Runnable)使用Runnable中的run方法;

讲完Handler构造函数,接下来就要重点讲讲Handler如何发送消息的相关方法了,Handler发送消息主要分为两种,一种是sendXXX()和postXXX()两种形式:

sendXXX相关方法介绍,源代码:

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
    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);
    }

Handler、MessageQueue、Looper和Thread原理简析_第2张图片

会发现sendMessageXXX和sendEmptyMessageXXX最终都是调用sendMessageAtTime方法将消息放入队列中;

postXXX相关方法介绍,源代码:

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }
    
    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

   public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    
    public final boolean postAtFrontOfQueue(Runnable r)
    {
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }

通过源代码我们会发现postXXX方法最终都是调用的sendMessageXXX方法,在postXXX方法中都调用了 getPostMessage(r)和 getPostMessage(Runnable r, Object token)方法最终目的都是生成Message对象,然后调用sendMessageXXX方法;

getPostMessage源代码

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

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

查看getPostMessage方法可以发现,该方法最终是生成了一个Message对象,Message对象携带了callback对象,最终postXXX方法将携带Runnable信息的Message传递给sendMessageXXX方法,最终调用sendMessageAtTime将消息加入到消息队列队列中,通过代码分析可以看到postXXX方法最终依赖sendMessageXXX方法;

我们通过下面的关系图更加清晰的postXXX和sendMessageXXX方法的关系:

Handler、MessageQueue、Looper和Thread原理简析_第3张图片

有一个特殊的postAtFrontOfQueue方法调用的是sendMessageAtFrontOfQueue方法,目的就是将消息在MessageQueue中的优先级提高,优先处理;

通过分析源代码我们会发现sendMessageXXX、sendEmptyMessageXXX和postXXX最终都是调用的sendMessageAtTime方法,那么接下来看一下sendMessageAtTime方法的源代码:

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

a.mQueue通过获取当前线程绑定的Looper,然后获取Looper中存放的消息队列;

mLooper = Looper.myLooper();

mQueue = mLooper.mQueue;

b.enqueueMessage()方法是将消息加入到队列中,源代码如下:

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

a.msg.target

对应绑定的是当前的Handler;

b.queue.enqueueMessage

对应的是Handler所绑定的消息队列,调用消息队列的enqueueMessage()方法将Message消息加入到队列中;

通过以上源代码的分析,我整理一下整个流程图,如下:

Handler、MessageQueue、Looper和Thread原理简析_第4张图片

以上是Handler接收Message到入队列的整个操作流程;

下面看一下Hander是如何从消息队列中取消息并且处理的:

我们分析源代码时发现Looper会有消息循环机制,调用loop方法以后会不断的从消息对中取消息,通过查看loop方法可以看到最终取到消息以后会调用如下代码msg.target.dispatchMessage(msg),最终调用Message绑定的Handler的dispatchMessage(msg)方法处理处理消息,简单分析一下dispatchMessage源代码:

 /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

a.首先检查Message中是否有Runnable信息,若有则调用线程中的run方法执行msg.callback.run(),这种方式是通过postXXX的方式加入到消息队列中的消息;

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

b.检查到Message不是通过postXXX方式加入的消息队列的,就是Message.callback==null的情况,判断是否实现Handler类中的Callback方法

public interface Callback {
        public boolean handleMessage(Message msg);
    }
若实现了,则调用Callback中的handleMessage方法处理消息;

c.如果我们在构造函数中没有传入Callback类型的对象,那么mCallback就为null,那么我们会调用Handler自身的hanldeMessage方法,该方法默认是个空方法,我们需要自己是重写实现该方法。

综合上面的情况我们会发现,处理消息会有优先级的区分,首先检查是否是通过postXXX方法添加到消息队列,然后检查是否实现Callback接口,最后才会调用Handler.handleMessage()方法处理消息;

3.Handler机制的流程图

Handler、MessageQueue、Looper和Thread原理简析_第5张图片

以上是我基于查看源代码总结的流程图,欢迎指正;

框架源码:https://github.com/aosp-mirror/platform_frameworks_base

参考:https://blog.csdn.net/iispring/article/details/47180325#commentsedit

你可能感兴趣的:(Android源码分析)