Handler

203 阅读5分钟

一、Handler是什么

Android中的消息处理机制。

Handler发送并处理与线程相关的Message和Runnable对象。

那么我们使用Handler可以做些什么呢?

二、Handler的用途

Handler主要有以下两种用途 1、延时处理消息 2、线程之间消息通信

知道Handler的用途后,我们该具体怎么使用Handler实现相应功能呢?

三、Handler的使用

我们在一、Handler是什么 中提到

Handler发送并处理与线程相关的Message和Runnable对象

因此我们从发送入手Handler的使用

首先我们来看官方handler API中和发送相关的Public methods

方法含义
post(Runnable r)将Runnable r添加到消息队列。
postAtTime(Runnable r, long uptimeMillis)将Runnable r添加到消息队列中,在特定时间uptimeMillis运行。
postDelayed(Runnable r, long delayMillis)将Runnable r添加到消息队列,在经过指定的时间后运行。
sendEmptyMessage(int what)发送只包含what值的消息。
sendMessage(Message msg)在当前时间之前的所有挂起消息之后,将消息推送到消息队列的末尾。
sendMessageAtTime(Message msg, long uptimeMillis)在绝对时间(以毫秒为单位)uptimeMillis之前,在所有挂起的消息之后将消息排入消息队列。
sendMessageDelayed(Message msg, long delayMillis)在时间(current time + delayMillis)之前的所有挂起消息之后,将消息排入消息队列。

*上表中仅列出关键方法,更多参考官方文档

由上表可见发送方法主要分为post和sendMessage两种。

我们来分析一下这两种方法的使用:

1、post是将Runnable对象加入到消息队列中,消息到达后将可以在Runnable对象中run方法收到回调(处理);

2、sendMessage是将Message对象加入消息队列中,同时需要实现Handler的handleMessage,用于处理消息。

以下是两种方法的通常用法示例:

首先是post方法:

// 1、 创建handler实例
private Handler handler = new Handler();

// 2、 使用post发送消息,并在run中做接收处理
handler.post(new Runnable() {
     @Override
    public void run() {
       // 相应处理
    }
});

然后是sendMessage使用:

// 1、 创建Handler的静态内部类子类
private static class MyHandler extends Handler {
    // 实现handleMessage 接收处理消息
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 根据msg.what处理消息
    }
}

// 2、创建Handler实例
private Handler mhandler = new MyHandler();

// 3、发送消息 - 一般在线程中
new Thread(){
    @Override
    public void run() {
        try {
            Message message = Message.obtain();
            message.what = 1;
            message.obj = message;
            mHandler.sendMessage(message);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}.start();

  • *以上使用示例仅仅是通常使用方式的示例,根据具体业务不同,可以有更多其他用法

好了,我们知道了如何使用Handler进行发送和接收消息。 那么接下来我们揭开Handler神秘面纱,研究下Handler是如何实现消息的处理的。

四、Handler如何实现线程间通信的呢

首先我们从发送消息开始入手。

1、发送消息

摘出Handler中几个关键的post和sendMessage方法:

    public final boolean post(Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    public final boolean postDelayed(Runnable r, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    
    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);
    }

由上代码可见,所有post和sendMessage方法最终都会调用sendMessageAtTime方法。

其中post方法中Runnable会通过getPostMessage()方法封装到Message中:

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

接下来看下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);
    }
    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)  {
        // 当前Handler对象赋值给Message的target
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

sendMessageAtTime中主要是做了一件事:将消息添加到消息队列。 同时将当前Handler对象赋值给Message的target。

其中MessageQueue变量取自mQueue,mQueue初始化时机在Handler构造方法中:

    // 使用当前线程looper
    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());
            }
        }
        // 1、mLooper初始化
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        // 2、获取mQueue变量
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    // 初始化时提供looper
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        // 获取mQueue变量
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

此处我们需要知道mQueue是由Looper提供的。

我们继续看MessageQueue是如何将Message加入队列的,看MessageQueue的enqueueMessage方法:

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
     
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
             
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

enqueueMessage方法主要是将消息插入链表: 1、mMessages为null或when为0,或when小于mMessages的when,则将msg插入链表头部,并赋值给mMessages 2、循环链表,直到找到节点p为null,或when小于p的when,将msg插入节点p之前

至此,msg消息已进入消息队列中(实际链表结构)。

接下来我们来了解处理消息的过程。

处理消息

我们从发送消息过程中知道,最终消息是放到MessageQueue中的mMessages链表结构中,那么我们根据mMessages来研究下读取消息并交给Handler处理的过程。

MessageQueue中next()方法就是用来处理读取过程的:

       Message next() {
        ...
        
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        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;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
                ...
            }
            ...
        }
    }

next()中关键部分是个无限for循环,有消息时从节点中删除并返回,无消息时陷入阻塞等待。

然后需要看调用next()方法的时机,我们之前知道Handler中的mQueue是从Looper中拿到的,那么就从Looper中看下next()调用的时机。

我们找到Looper中loop()方法有调用MessageQueue的next()方法

    /**
     * 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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        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 traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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.recycleUnchecked();
        }
    }

loop()中首先通过myLooper()方法获取looper对象,此处通过ThreadLocal获取当前线程Looper,此处也是回到原始线程处理消息的关键。

     /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

loop()中是个无限for循环,循环中第一句就是调用MessageQueue的next()方法,并且可能出现阻塞(上面讲netx()方法中无消息时阻塞等待)。

Message msg = queue.next(); // might block

读取到Message消息msg后,会调用target.dispatchMessage(msg)方法。 msg.target.dispatchMessage(msg);

前面我们知道Message中target为当前Handler对象。那么再看Handler中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);
        }
    }

此处判断分3中情况 (1)callback不为null,调用handleCallback

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

前面我们知道,message的callback即post方法中的runnable对象。

在runnable对象run方法中处理消息。

(2)callback为null,mCallback不为空,调用mCallback.handleMessage

    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        public boolean handleMessage(Message msg);
    }

mCallback回调中处理消息。 (3)mCallback为null或mCallback的handleMessage返回false,调用Handler的handleMessage方法

     /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

子类中实现handleMessage并处理消息。

至此,Handler实现消息发送和处理的过程全部完成了。