原创源码角度分析Android的消息机制系列——Handler的工作原理

Posted 琳茹的技术轮子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创源码角度分析Android的消息机制系列——Handler的工作原理相关的知识,希望对你有一定的参考价值。

ι 版权声明:本文为博主原创文章,未经博主允许不得转载。

 

先看Handler的定义:

/**
 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread‘s {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread‘s message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * 
 * <p>There are two main uses for a Handler: (1) to schedule messages and
 * runnables to be executed as some point in the future; and (2) to enqueue
 * an action to be performed on a different thread than your own.
 * ……….
 * */
public class Handler {
……..
}

由源码中对Handler的定义以及注释,我们可知,Handler主要就是用来发送和处理消息的。每一个Handler的实例都和一个线程以及该线程的MessageQueue相关联。Hadnler主要有2个作用:①在未来某个时刻去发送或处理Message或Runnable(post方法)②在另一个线程中去处理消息(send方法)。

 

再看Handler的构造方法:

public Handler() {
        this(null, false);
    }
…….
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());
            }
        }
 
        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;
    }
 ……

由构造方法可知,当前线程中没有Looper时,若创建Handler对象,则会抛出"Can‘t create handler inside thread that has not called Looper.prepare()"异常。所以,必须要在有Looper的线程中创建Handler,否则,程序将抛出异常。

 

Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现。下面来看一系列post方法:

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

通过源码,我们可以知道,post的一系列方法最终还是通过send的一系列方法来实现的。

 

下面看send的一系列发送消息的源码:

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 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);
    }

由源码可知,Handler发送消息的过程,其实就是向消息队列中插入了一条消息。

由MessageQueue的工作原理和Looper的工作原理我们可以知道,当MessageQueue中插入了新的消息后,next方法就会返回该消息给Looper,Looper接收到消息并开始处理消息,但最终Looper是通过调用Handler的dispatchMessage方法来处理消息的,即消息最终还是交给了Handler去处理。

 

下面来看Handler的dispatchMessage方法的源码,如下:

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    private static void handleCallback(Message message) {
        message.callback.run();
    }

首先,判断了Message的callback是否为null,若不为null,则调用handleCallback方法。

Message中有属性:  /*package*/ Runnable callback;  那么,message.callback即Handler的post方法所传递的Runnable参数。再结合handleCallback方法的源码可知,handleCallback方法其实就是开启了一个子线程,去处理post方法。

再看dispatchMessage方法的源码,若Message的callback为空,则判断mCallback是否为null,由Handler的源码:

final Callback mCallback;
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

可知,Callback就是一个接口,而且其中定义了handleMessage方法。由此我们可以联想到,当需要获取一个Handler实例时,我们除了可以继承Handler,重写handleMessage方法外,我们还可以通过实现Callback 接口,然后实现接口中的handleMessage方法来实现。

接着来看dispatchMessage方法的源码,若mCallback为null,最后还是调用handleMessage方法来处理消息。

在开发过程中,当用Handler处理消息时,我们一般是需要重写handleMessage方法的,处理消息的逻辑由我们自己来写。

 

 

以上是关于原创源码角度分析Android的消息机制系列——Handler的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

原创源码角度分析Android的消息机制系列——Handler的工作原理

原创源码角度分析Android的消息机制系列——ThreadLocal的工作原理

原创源码角度分析Android的消息机制系列——MessageQueue的工作原理

原创源码角度分析Android的消息机制系列——ThreadLocal的工作过程

从架构师的角度分析Android Handler 源码的正确姿势

Android消息机制源码分析