Handler运行机制

2018-01-01  本文已影响0人  阪本先生的围巾

Handler运行机制是Android消息处理机制的上层接口. 依靠Looper, MessageQueue, Message支撑/协作.

在主线程中不能放置耗时任务, 否则会引起ANR. 所以一般耗时任务会放在子线程当中. 由于Android开发规范, 在子线程中不能进行UI操作. 不可避免地涉及进行线程之间通信问题. 所以有人说, Handler运行机制就是用来处理UI线程与子线程之间的通信的. 这仅仅是Handler运行机制的一个应用场景. 比如还可以实现子线程向子线程发送消息, 可以参考下这篇文章.

四个重要角色

Message

Message是消息的载体, 比较重要的两个字段是objwhat字段, obj就是需要传递消息的内容, what标志消息的类型, 方便在接收的时候处理.

MessageQueue

存储Meesage的单链表, 向外提供读取next方法, 与enqueueMessage入队操作.

Looper

维护MessageQueue, 开始工作时, 不断从MessageQueue中取出Message分发给他们的target(其实就是他们对应的handler). 一个线程中只能有一个Looper对象.

Handler

消息的发送者与消息的处理者

一个经典的例子

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

这里通过继承Thread,创建了一个LooperThread的线程类, run方法中先调用了Looper.prepare(), 然后创建了一个Handler对象, 最后调用了Looper.loop()方法.

接下来, 我们通过源码分析看看究竟发生了什么.

Looper.Prepare

    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方法可以重载, 先会判断sThreadLocal.get()是否为空, 为空的话, 先new Looper(quitAllowed)创建了一个Looper对象, 然后把这个Looper对象保存在了sThreadLocal中. 可以想象当我们再次在当前线程调用Looper.prepare方法时, 这时的sThreadLocal.get()就不为空了, 会向我们抛出一个Only one Looper may be created per thread异常. 由此可以保证我们每个线程最多拥有一个Looper对象.

刚才构造Looper对象的过程中, 究竟又做了什么呢?
我们看看Looper的构造方法

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

可以看到内容只有两行. 分别为Looper的两个成员变量赋值, 创建了一个MessageQueue, Looper绑定了当前线程.

总结下就是: Looper.prepare方法在当前线程中创建了一个Looper对象, Looper对象的创建又导致了MessageQueue对象创建. 并且绑定当前线程. (Looper和MessageQueue在一个线程中最多有一个)

创建Handler对象

Handler对象的创建我们直接来看Handler的构造方法.

       /**
         * Default constructor associates this handler with the {@link Looper} for the
         * current thread.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         */
        public Handler() {
            this(null, false);
        }
    
        /**
         * Constructor associates this handler with the {@link Looper} for the
         * current thread and takes a callback interface in which you can handle
         * messages.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         *
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Callback callback) {
            this(callback, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one.
         *
         * @param looper The looper, must not be null.
         */
        public Handler(Looper looper) {
            this(looper, null, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one and take a callback
         * interface in which to handle messages.
         *
         * @param looper The looper, must not be null.
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }
    
        /**
         * Use the {@link Looper} for the current thread
         * and set whether the handler should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with respect to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        public Handler(boolean async) {
            this(null, async);
        }
    
        /**
         * Use the {@link Looper} for the current thread with the specified callback interface
         * and set whether the handler should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with respect to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param callback The callback interface in which to handle messages, or null.
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        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;
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one and take a callback
         * interface in which to handle messages.  Also set whether the handler
         * should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with respect to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param looper The looper, must not be null.
         * @param callback The callback interface in which to handle messages, or null.
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }

可以看到Handler的构造方法有好几个, 其实做的工作, 不外乎为他的各个成员变量赋值mLooper,mQueue,mCallback,mAsynchronous. 分析最复杂的Handler(Callback callback, boolean async)方法. Looper.myLooper()方发获得了一个Looper对象, 这个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();
        }

查看源码看到sThreadLocal.get(), 原来就是从我们在Looper.prepare()中存起来的Looper, 如果为空, 说明我们的prepare方法根本没有执行. 抛出Can't create handler inside thread that has not called Looper.prepare()异常. 接下来Handler的构造方法还做了一件事, 把Looper中维护的MessageQueue取出来赋值给了mQueue字段.

总结下: 获取当前线程的Looper对象取出来, 并把他和他维护的MessageQueue赋值给了Handler的成员变量.

这里有个问题: void handleMessage(Message msg)又是怎样被调用的呢?别急, 让我们看看Looper.loop()方法.

Looper.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 traceTag = me.mTraceTag;
                if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
                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();
            }
        }

可以看到在像Handler的构造方法一样, 先获得当前线程得Looper对象. 如果为空, 那一定又是没有prepare. 接下来可以看到for (;;) {}这样一个结构, 一个死循环, 不断获取nextMessage, 直到Message为空.

这里有个问题: 一直在说从队列中不断取Message, Message是多久放入队列的?

Message的入队时通过Handler对象的sendxxx类与postxxx类方法实现的.

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

可以看到最后都执行了boolean sendMessageAtTime(Message msg, long uptimeMillis)方法. 可以看到这里最终调用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);
        }

这就时我们想要的入队操作. 值得留意的是这里的msg.target = this, 入队的Message标记了发送他的Handler.

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

可以看到这里多调用了一个getPostMessage(r)方法. 这个方法就是将我们的Runnable对象封装为Message对象的关键.

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

可以看到这里获得一个Message后, 将Message的callback字段设置为了Ruannable对象. 这下就豁然开朗了.

接下来接着看在MessageQueue中拥有Handler发送来的消息后, 会如何进行操作. 在死循环中. msg.target.dispatchMessage(msg) 让msg的target(也就是发送他的Handler)去分发事件.

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

这里的逻辑就非常清晰了, 刚才想弄清楚的Handler的handleMessage就是再这里最后调用的. 除此之外, 消息的分发还有两条路径msg.callbackmCallback.handleMessage(msg). msg.callback还记得吗?就是postxxx类消息发送的Runnable对象. mCallback.handleMessage(msg)中的mCallback则是在Handler重载的构造方法的参数. 这里一旦设置了回调,并且其handlerMessage返回值为true, 就可以实现对Hadnler的handlerMessage的拦截.

ps: 有什么疏漏或者错误的地方还请各位指出.

参考:

上一篇 下一篇

猜你喜欢

热点阅读