Handler源码分析

Handler的作用

Android消息机制

我们都知道Android应用程序的UI的绘制都是在主线程(UI线程)进行的。如果在主线程做一些耗时操作会阻塞主线程的进行,耗时操作主要包括网络访问,大量计算,文件读写等等情况,会造成UI卡顿,严重的情况会造成应用程序ANR。所以我们上面说的这些耗时操作不能放在主线程中进行。我们在处理这些潜在的耗时操作时,会新开一个线程去处理这些事情。

当非主线程执行完操作之后,我们可能要把操作结果拿出来显示到界面上。这时候结果在非主线程中,然而绘制界面的线程是在主线程。怎么让主线程拿到非主线程的结果呢?

这时候,Handler的作用就体现出来了。我们通过Handler把非主线程的结果拿出来放到主线程不就可以了嘛。主线程通过Handler拿到结果后更新UI界面就OK啦。具体怎么通过Handler放入主线程,主线程怎么通过Handler获取结果执行的请看下面分析。

Handler原理

相关Java类

ActivityThread

我们都知道,在Java中程序的主函数叫做main函数,是Java程序执行的唯一入口。Android应用层代码是用Java写的,所以Android执行Java代码时首先会执行main函数。那么Android执行的main函数在哪个类中呢?

Android执行的main函数在ActivityThread:

 public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        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());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("");

        Looper.prepareMainLooper();

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

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

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

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

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

从上面代码中看到main函数的代码量不大。关键代码如下:

Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
    sMainThreadHandler = thread.getHandler();
}
Looper.loop();

Looper

这个类称为消息循环器,主要作用是创建消息队列(MessageQueue),把自身对象绑定到当前Thread,然后不断轮询消息队列,并把消息队列中的消息出队,交给与消息对应的Handler处理。

MessageQueue

这个类称为消息队列,数据结构为队列,维护消息队列状态,根据入队时间(when)对消息(Message)进行的入队或出队操作。还有个功能就是添加或删除SyncBarrier。

Message

这个类称为消息,是某个具体消息的载体,它实现了Parcelable接口,所以能做本地化存储。Message是封装了消息触发的时间(when),消息的类型(what),消息中具体携带的对象(obj,data),消息的处理者(Handler)等。

Handler

这个类称为消息的处理者,通过它可以发送消息,移除消息,对某个消息进行处理。

Handler运作流程

源码分析

从ActivityThread的main函数开始。

//创建Looper,MessageQueue,把当前线程和Looper对象绑定
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
    //获取主线程的Handler,此Handler用于处理系统消息
    sMainThreadHandler = thread.getHandler();
}
//开始轮询消息
Looper.loop();

Looper.prepareMainLooper方法中重要代码是执行了prepare方法,其作用是创建Looper和在Looper中创建MessageQueue,并通过ThreadLocal把当前线程和Looper绑定在一起,作用是让一个线程只能对应一个Looper对象。此Looper为主线程的Looper,所以只要是在主线程中创建的Handler发送的消息,都会进入此Looper的消息队列。

public static void prepareMainLooper() {
        //创建Looper,并绑定到当前线程
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //获取刚创建的主线程Looper
            sMainLooper = myLooper();
        }
    }
 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //通过ThreadLocal把Looper和当前线程绑定
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper.loop() ;

 /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        //获取当前线程的Looper
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //获取当前线程中Looper的消息队列
        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();
        }
    }

上面代码Message msg = queue.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;
                //处理SyncBarrier,跳过同步消息,只处理异步消息
                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;
        }
    }

如果从消息队列里取出了一个消息,下一步就做消息的分发处理 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);
        }
    }

从上面代码可知,当Message里面设置了callback,就执行Message里的callback回调方法,否则当Handler里面的mCallback!=null就执行mCallback,当mCallback==null时,调用Handler自身的handleMessage方法处理消息。

以上是消息处理的流程,下面分析下通过Handler发送消息。
我们通常使用Handler发送消息的方法一般有:

public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) 
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) 
//以下是post方法
public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)

这些方法最后调用的都是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);
    }

Handler的enqueueMessage方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //设置Message的target为当前Handler对象
        msg.target = this;
        //判断消息是否是异步的
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //根据消息的时间加入消息队列
        return queue.enqueueMessage(msg, uptimeMillis);
    }

MessageQueue的enqueueMessage方法

boolean enqueueMessage(Message msg, long when) {
        //非系统发送的消息msg.target不能为空,否则会抛异常
        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;
    }

流程图

Handler源码分析_第1张图片
这里写图片描述

Handler相关扩展

HandlerThread

IntentService

总结

Handler消息机制框架设计的非常好,我们在使用过程中,只需要自定义一个Handler,使用其发送消息和处理消息就行了,其余的不用我们去操心。当我们明白了其原理之后,后面使用Handler更得心应手。

Handler消息机制中很多细节这里还没有介绍,等之后对Handler有了更深的了解时,会慢慢补充。

思考

  • 非主线程中怎么使用Handler
  • View UI更新用到Handler的地方
  • 自定义Handler

参考

  • 深入Android消息机制
  • Android中关于Handler的若干思考
  • 为什么我们可以在非UI线程中更新UI
  • View与窗口:AttachInfo
  • Android更新Ui进阶精解

你可能感兴趣的:(Handler源码分析)