Android基于源码分析Handler的消息机制

Handler介绍

    handler是Android系统中提供的一种异步回调机制,通过使用handler,我们可以完成一些耗时的任务,然后通知相关的页面做出相应的改变。在我们工作的场合中,大部分开发者会认为handler就是用来更新UI的,这样说没错,然而这只是从我们开发的场景去看待handler,其实Android底层在进行跨进程通信中(ActivityManagerService或WindowManagerService),也同样大量的通过使用handler来执行相关的操作。好,废话不多说,今天,我主要是从源码的角度来讲解handler的运行机制(基于Android4.4源码)。

Message、Handler、MessageQueue、Looper和 Thread的介绍

    Message:熟称消息,这其中包含了消息ID,消息处理对象以及处理的数据,是一个消息的最小单元。由MessageQueue统一管理,最终由handler处理。

    Handler:处理者,负责message的发送和处理。

    MessageQueue:消息队列,用来存放handler发送过来的消息,并将message以单链表的形式串联保存起来,并等待looper抽取。

    Looper:消息循环者,不断的从MessageQueue中拉取message来执行,一个Looper对应一个MessageQueue,但是可以对应多个handler。

    Thread:线程,负责调度整个消息循环,也就是消息循环执行的场所。

Android消息机制原理基于源码介绍

    介绍了这些基本的概念后,下面我们言归正传:通常,咱们在使用handler的时候先会声明并创建一个handler,并重写handleMessage,方法如下所示:

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch (msg.what) {
			case 0:
				break;
			case 1:
				break;
			case 2:
				break;
			default:
				break;
			}
		}
	};

在使用handler发送消息的时候代码如下:

    Message msg = Message.obtain();
    msg.what = 0;
    msg.obj = mData;
    mHandler.sendMessage(msg);

代码里面的msg.what = 0和msg.obj = mData这里只是举例子哈,是这个意思大家能理解就行。当我们按住ctrl+鼠标左击sendMessage(msg)这个方法的时候,就会顺利得进入到今天要讲的主题啦:

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

代码在handler类的501行(下面的我就都以我的源码行数为准了,再重申一下我看的是Android4.4的源码),这个类没什么,我们直接往下看:

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

在handler类的561行,这个方法里面就是赋值了一个long行的参数,没什么,我们接着看sendMessageDelayed(Message msg, long 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类的587行,这里此方法将mQueue赋值给了局部变量queue,下面的也什么难理解的,那,这个mQueue哪来的呢,我们找找:

 final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;

从handler类的736行开始,声明了这个几个成员变量,但这只是声明,没有赋值,好,咱们接着看:

 /**
     * 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 represent 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 represent 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;
    }
在handler类的106行,我特意复制了一堆的方法,这里也不再熬述Java语法,我们只管看到188行的public Handler(Callback callback, boolean async)这个方法,大意就是我们创建handler后进入到构造方法,然后来到这个方法里面,这里面就有我们需要找的mQueue,我们看到,mQueue = mLooper.mQueue,这行,原来mQueue是从Looper这个类里面得到的,mLooper = Looper.myLooper(),至于为什么直接就从Looper.myLooper()得到呢:

    public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

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

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

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

这段代码是ActivityThread里面的main(),也就是咱们在启动Activity的时候会执行到这个方法里头,多的也不看,这里面有Looper.prepareMainLooper()这行代码,好,我们看看Looper中的这段代码:

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = 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();
    }

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

prepareMainLooper()在Looper类的88页,myLooper()在Looper类的161页。实质上主线程里面就直接创建好的looper,Looper中有个构造函数,构造函数里面创建了MessageQueue对象,所以一个Looper对象对应一个MessageQueue对象来源与此。这也是为什么我们在UI线程中直接用handler不需要创建Looper的原因。上面AcrivityThread中有个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
            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();
        }
    }

在looper类的110行。看重点,里面有个for (;;)的循环,这里暂时不对里面的逻辑分析,从这里就知道了looper创建好了之后,就一直不停的执行了。接着回到handler类的587行

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

mQueue知道怎么来的了,Looper也知道怎么来的了,然后再查看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);
    }

在handler类的621行。这里有个很重要的细节,就是msg.target = this,也就是说把当前handler对象传递给了msg.target,我们看看msg.target是什么:

    /*package*/ Handler target; 

这是Message类第89行的代码,这里是把msg的成员变量target赋值为当前Message坐在的Handler。接着看return queue.enqueueMessage(msg, uptimeMillis)这行,这里就到了MessageQueue类里面了:

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

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

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

也是看重点,这个方法下面也有个无限循环,就是说不停的往当前的MessageQueue中插入message,这里采用的是单链表结构将message对象插入到消息队列:prev = p;p = p.next;msg.next = p;prev.next = msg;这几行代码对于有过数据结构知识的同学来说应该不难理解,仔细琢磨下不难。说到这里的时候,我们回顾下上面所说的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
            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();
        }
    }

再贴一遍吧,这里来详细分析下:Looper me = myLooper(),final MessageQueue queue = me.mQueue这两行代码,前面说了looper创建的同时也创建了MessageQueue对象,即一个Looper中对应有一个MessageQueue对象。这里直接获得到Looper中的MessageQueue所以在Looper的loop()方法中这个looper通过MessageQueue不断的拉取消息队列中的消息。执行Message msg = queue.next()这行代码,我们再看看MessageQueue中:

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

            // We can assume mPtr != 0 because the loop is obviously still running.
            // The looper will not call this method after the loop quits.
            nativePollOnce(mPtr, 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 (false) Log.v("MessageQueue", "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("MessageQueue", "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;
        }
    }

这是MessageQueue类的128行,大意就是从单链表中不断的获取message,然后返回这个message。到这里,实质上就是说Looper在主线程里面创建好了后,开启无限循环模式,不停得从MessageQueue中拉取message,当有handler发送消息时,就通过MessageQueue中的 enqueueMessage(Message msg, long when)此方法以单链表的形式存储了message,这个时候无限循环的looper中的 Looper.loop()方法中Message msg = queue.next()的msg取到之后就不为空 ,然后执行到loop()中的这一行:

msg.target.dispatchMessage(msg);

前面说了target就是handler对象,所以当looper从MessageQueue中获取到一个message后,在通过message的handler去把这个message分发处理:

    /**
     * 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类的第93页,上面的if和else我们不用管,那是基于handleCallback处理的,这里我们没有创建相关Callback类的话,就直接看下面的handleMessage(msg)这行:

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

在handler类的第84页,从源码中可以得出,这个类实际上需要在我们自己创建handler的类中实现,还记得博客开头咱们自己new的handler么,里面的确有这个重写的方法。相当于在loop()中获取到MessageQueue中的message后,msg.target.dispatchMessage(msg)其实分发执行到handler的handleMessage()方法里面,而这个方法在应用自己创建的页面实现,所以整个handler的运行机制到这就分析完了。



阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoujian1990520/article/details/49929375
个人分类: 个人技术学习
上一篇Android基于源码分析AsyncTask的工作流程
下一篇BlockingQueue的使用
想对作者说点什么? 我来说一句

Android Message

2011年10月15日 45KB 下载

Android Handler 图片浏览器

2014年12月13日 1.83MB 下载

android消息机制

2011年12月20日 74KB 下载

Android消息机制

2014年05月15日 332KB 下载

android消息机制中几个类的源码

2015年05月06日 18KB 下载

android 多线程 looper handler

2011年07月31日 48KB 下载

handler消息机制详细教程

2015年11月28日 126KB 下载

Handler消息机制和异步加载

2013年04月22日 836KB 下载

Android handler message奇怪用法详解

2016年08月02日 104KB 下载

没有更多推荐了,返回首页

关闭
关闭