Handler 消息机制

Android 的消息机制主要由 Handler,Looper,MessageQueue,Message 等组成,而 Handler 的运行主要依赖后三者;

源码分析

Handler 的消息处理主要有五个部分, Message, Handler, MessageQueue, Looper, Threadlocal.

方法作用
MessagerMessage 是线程之间传递的消息,他可以在内部携带少量的数据,用于线程之间交换数据, Message 有四个常用字段,what,arg1,arg2,obj.其中what,arg1,arg2可以携带整型数据,而 obj 可以携带 object 对象.
Handler它主要用于发送和处理消息的发送消息一般使用的是sendMessage() 方法,还有其他一系列的sendXXX方法,但是最终都是调用了 sendMessageAtTime() 方法, 除了 sendMessageAtTime() 这个方法而发出的消息经过一系列的辗转处理后,最终会传递到 Handler的handleMessage() 方法中。
MessageQueueMessageQqueue 是消息队列的意思,它主要用来存放所有通过 Handler 发送的消息,这部分的消息会一直存在消息队列中,按进入队列的时间顺序依次等待被处理. 每一个线程中都会有一个 MessageQueue 对象.
Looper每个线程通过 Handler 发送的消息都保存在 MessageQueue 中,而 Looper 通过调用 loop() 方法,就会进入一个无线循环中,然后发现一个 MessageQueue 中存在一条消息就将它取出来,并传递给 Handler.handlermessage() 方法中.每一个线程只会存在一个 Looper 对象
ThreadLocalMessageQueue 对象,和 Looper 对象在每个线程中都会有一个对象,那么我们怎么保证他只有一个对象呢?单利?静态?其实使用通过 ThreadLocal 来保存.ThreadLocal 是一个线程内部的数据类,他可以在指定线程中存储数据,数据存储后,只能由指定的线程获取,而其他的线程则不可获取到数据.

在了解到这些基本的概念以后我们就来深入的看一看 Handler 的工作机制.

MessageQueue 的工作原理

MessageQueue 消息队列是通过一个单链表的数据结构来维护消息链表.下面最主要看 enqueueMessage 方法和 next() 方法.

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

可以看出来,这个方法主要是根据时间顺序向表单中插入一条消息.
那么 next() 又是用来干什么呢?
我们继续看下去:

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

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

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

在 next 中有一个关键方法 for (;;) 对就是这个死循环,慢慢梳理代码我们不难看出如果有消息返回就从链表中移除.没有消息的时候就会一直柱塞在这里

Looper

在一个 Android 启动应用的时候,会创建一个主线程, 也就是UI线程.而这个主线程 ActivityThread 中的一个静态的 main 方法. 这个 main 方法也就是我们应用程序的入口点. 我们来简单的看一下这个 main 方法.

public static void main(String[] args) {

    ......

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    ......

    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

从上面的方法中我们可以看出来,使用了 Looper.prepareMainLooper() 方法为主线程创建了 Looper 以及 MessageQueue, 并通过Looper.loop() 来开心主线程的消息循环.

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

这个方法中调用了 prepare(false);方法和 myLooper(); 方法

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

在这里 sThreadLocal 对象保存了一个 Looper 对象,以防止被调用两次.sThreadLocal 对象是 ThreadLocal 类型,因此保证了每个线程中只有一个 Looper 对象。
那么 Looper 到底干了什么?

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

果不其然,在 Looper 的构造函数中创建一个 MessageQueue 对象和保存了当前的线程.从之前的代码中可以看出一个线程只能有一个 Looper 对象,而 MessageQueue 又是在 Looper 构造函数中创建出来的,因此每一个线程也只有一个 MessageQueue 对象;
还有一个 prepare 的重载方法;

public static void prepare() {
    prepare(true);
}

prepare() 仅仅是对 prepare(boolean quitAllowed) 的封装,这里就是解释了主线程不需要调用 Looper.prepare() 方法了.因为主线程在启动的时候已经很贴心的帮我们调用了啊!

然后在说说我们在 Looper.perpareMainLooper() 方法中的 myLooper()

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

这串英文是什么意思呢? 让我们请出我们可爱谷歌娘:返回与当前线程关联的Looper对象。 如果调用线程未与Looper关联,则返回null。
有没有很清楚一下就明白了.就是取出我们当前线程中的 Looper 对象,保存在 sMainLooper 瞧瞧这命名方式多简单易懂;

我是不是忘记了什么?
哦!对了还有一个方法: Looper.loop() main 还调用了这个方法是用来干什么的呢?

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

快看是 next() 方法,是不是好像在刚刚的 MessageQueue 方法中看到了?
对就是这样,从这个方法里进入一个无限循环,不断的从 MessageQueue 的 next 方法获取消息,而next方法是一个阻塞操作,当没有消息的时候就一直在阻塞,当有消息通过 msg.target.dispatchMessage(msg); 这里的msg.target其实就是发送给这条消息的Handler对象。那么我们就去看看 Handle 又干了什么;

Handler

构造方法

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

怎么都要传递 Looper 我们没有怎么办,那就看看不需要传递 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());
        }
    }

    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 为 null 竟然抛出了 Can't create handler inside thread that has not called Looper.prepare() 异常,这样我们知道为什么在子线程中使用 Handler 时要手动调用 Looper.prepare() 方法了,原来是用来创建一个 Looper 对象.那么主线程为什么不用呢?因为服务周到的主线程已经在创建的时候就自己调用了 Looper.prepare() 方法了.

Handler 的工作主要事实包含发送和接收过程.其中 post 和 send 的一系列方法主要是用俩发送消息.但是 post 其实最终也会通过 ssend 的一系列方法来实现的. 而 send 的一系列方法最终会通过 sendMessageAtTime 方法来实现.来我们看看 send 的一系列方法:

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

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

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

    public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
    }

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

这里我们可以看出,handler 发送的消息其实就是将消息插入消息队列,在 Looper 的 loop 方法中从 MessageQueue 中取出并调用 msg.target.dispatchMessage(msg) ;而这个其实就是就是在调用 Handler 的 dispatchMessage(msg) :

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

先最一个非空判断,非空时调用了 handleCallback(msg); 来处理消息,那么 msg.callback 是什么东西啊? 其实这里的 msg.callback 就是一个 Runnable对象, 也就是 Handler 发送过来的 post 对象.先看看 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));
}

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

好了我们在看看 msg.callback 非空时 handleCallback(msg) 是做了什么:

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

emmmmm… 果然就是很简单的回调了 Runnable 对象的 run 方法. 其实吧我们去看看 Activity 中的 runOnUiThread 和 View 中的 postDelayed 方法也是使用了同样的原理,我们先看看 runOnUiThread 方法:

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

View 的 postDelayed 方法:

public boolean postDelayed(Runnable action, long delayMillis) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.postDelayed(action, delayMillis);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
    return true;
}

实质上都是在 UI 线程中执行 Runnable 中的 run 方法.

在回来看看 msg.callback 为空的时候会对 mCallback 进行非空判断,而 mCallback 又使用一个接口的引用:

/**
 * 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 来实现.

总结

首先在主线程创建一个 Handler 对象 ,并重写 handleMessage()方法。然后当在子线程中需要进行更新 UI 的操作,我们就创建一个 Message 对象,并通过 handler 发送这条消息出去。之后这条消息被加入到 MessageQueue 队列中等待被处理,通过 Looper 对象会一直尝试从 MessageQueue 中取出待处理的消息,最后分发会 Handler 的 handlerMessage() 方法中。

最后来一张我话的流程图:

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值