首先明白3个问题:Handler 是什么?Handler 拿来干什么?Handler 怎么使用?

前言:为什么会出现Handler?

    我们都知道Android 的UI线程(即主线程)是线程不安全的,一切引起UI变化的操作均需在主线程中执行,而更新UI的操作往往是在一些耗时操作之后的,比如网络请求、IO操作、文件读写等这些耗时操作必须在子线程执行,而Android的开发规范规定我们不能在子线程中访问UI控件,否则会触发程序异常,而Handler 就是为了解决在子线程中访问UI的这个问题而诞生的。

1、问题:为什么Android 的UI线程(主线程)是线程不安全的?为什么Android 采用单线程模型来处理UI操作?
    答:android UI 中是由invalidate()来更新界面,而invalidate()方法是线程不安全。
详解:
        更新UI只能是主线程的工作,子线程更新UI是线程不安全的,所以android里非主线程操作主UI就会报错。这是因为多线程中并发访问可能会导致UI处于不可预期的状态,即子线程可以有好多个,但如果每个子线程都直接对UI元素进行操作,界面会混乱不堪(例如多个线程同时操作一个控件可能会有冲突发生,控件不知道该执行哪一个的命令)。
         单线程模型:线程会面临安全问题,虽然可以通过加锁机制来解决线程的安全问题,但是加锁首先会使UI访问的逻辑变得复杂,其次降低运行效率,鉴于这两个缺点,最简单且高效的做法就是采用单线程模型来处理UI操作,所以主线程(UI线程)并没进行加锁限制多线程访问, 可能这就是“出于性能优化考虑”。

2、问题:既然没有对多线程访问进行限制,而且子线程依然有进行UI操作的需求,那么该如何解决呢?
   所以Android规定只能在主线程中进行UI元素的更改,即所有子线程如果要修改用户界面,就必须先通知我(主线程),我来帮你们完成 。所以 android 的 UI 操作一定要在 UI 线程中执行。

Android的单线程模型有两条原则:
  1.不要阻塞UI线程。
  2.不要在UI线程之外访问Android UI 控件

拓展:
3、问题:Android是怎么知道你是不是在子线程中访问UI的?
答:ViewRootImpl 对UI 的操作进行了验证,这个验证是通过ViewRootImpl 的checkThread 方法来完成的,如下所示:

void checkThread(){    if(mThread!=Thread.currentThread()){    throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can                                             touch its views.");    }}

 

前面介绍完 Handler 的由来和 Android 的UI 线程,现在开始我们的正菜,详解Handler 机制:

Handler 是什么?

    Handler 是Android 消息机制的上层接口,它的主要作用是将一个任务切换到某个指定的线程中去执行,是为了解决子线程中无法访问UI的问题而设计的。说白了它就是一个传递消息、处理消息的工具,它和它的两个兄弟 MessageQueue、Looper 齐心协力才能实现上述的功能。

    Android 的消息机制主要是指 Handler 的运行机制和Handler所附带的MessageQueue和Looper的工作过程,Handler 的运行需要底层的 MessageQueue(消息队列)和Looper 的支撑。

Handler、Message、MessageQueue、Looper 之间的关系
1. Message(消息的载体)
          Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了Message的what字段,除此之外还可以使用arg1和arg2字段来携带一些整型数据,使用obj字段携带一个Object对象。
2. Handler(消息的消费者,即发送和处理)
          Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中,最终存储在MessageQueue中。Handler 的主要作用就是将一个任务切换到某个指定的线程中去执行。是为了解决子线程中无法访问UI 的问题。
3. MessageQueue(消息的存储器)
         MessageQueue是消息队列的意思,它采用单链表的数据结构来存储消息列表。它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
4. Looper(消息的处理器)
          Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。
        打个比方:传送带传送物品,Looper就是传送带的电机,它会无限的循环查询传送带MessageQueue中存储的物品,Message就是存储消息的物品,由Handler在上游发送(sendMessage),也由Handler在下游取出消费(handleMessage)

拓展:Handler 如何获取到当前线程的Looper?
        ThreadLocal 可以在不同的线程中互不干扰的存储并提供数据,通过ThreadLocal 可以轻松的获取到每个线程的Looper,线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper。主线程(即UI 线程)就是ActivityThread,ActivityThread 在被创建时就会初始化Looper,者也是在主线程中默认可以使用Handler 的原因。

Handler 的工作原理:Handler 创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper,那么就会报错,如下所示:

E/AndroidRuntime: FATAL EXCEPTION: Thread-50003        Process: com.example.cyf.myapplication, PID: 2223        java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()        at android.os.Handler.(Handler.java:200)        at android.os.Handler.(Handler.java:114)        at com.example.cyf.myapplication.MainActivity$3$1.(MainActivity.java:0)        at com.example.cyf.myapplication.MainActivity$3.run(MainActivity.java:56)        at java.lang.Thread.run(Thread.java:818)

怎么解决:
1、为当前线程创建一个Looper,一个线程只能有一个Looper 对象 ,   
2、在一个有Looper 的线程中创建 Handler

        Handler 创建完毕后,通过Handler 的post 方法将一个 Runnable 投递到Handler 内部的Looper 中去处理(最终也是通过 send 方法来完成的),也可以通过 Handler 的 send 方法发送一个消息,这个消息同样会在 Looper中处理。当Handler 的send 方法被调用时,他会调用MessageQueue 的 enqueueMessage 方法将这个消息放入消息队列中,然后Looper 发现有新消息到来时,就会处理这个消息,最终消息中的Runnable 或者Handler 的 handleMessage 方法就会被调用,注意Looper 是运行在创建Handler所在的线程中的

Android 的消息机制之 Handler_第1张图片

MessageQueue 消息队列的工作原理:
        其主要包含两个操作:插入和读取(读取本身会伴随着删除操作),其分别对应着 enqueueMessage 和next 方法,其中enqueueMessage 方法的作用是向消息队列中插入一条消息,而next 的作用是从消息队列中取出一条消息并将其从消息队列中删除。

MessageQueue  是通过一个单链表的数据结构来维护消息队列的,单链表在插入和删除上比较有优势。

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

    其主要实现单链表的插入操作

MessageQueue  的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) {//退出消息队列直接返回null,跳出循环                    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 方法是一个无限循环方法,如果消息队列中没有消息,则next 方法会一直阻塞在这里,当有新消息到来时,next 方法会返回这条消息,并将其从单链表中删除。

Looper 的工作原理:
    在Android 消息机制中扮演者消息循环的角色,就是不停地从MessageQueue 中查看是否有新的消息,如果有就立即处理,没有则一直阻塞在哪里,在Looper 的构造方法中,会创建一个 MessageQueue 消息队列,并将当前的线程保存起来,其源码如下:

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

    Handler 的工作需要Looper,没有Looper的线程就会报错,Looper的创建通过 Looper.prepare() 为当前线程创建一个Looper,通过Looper.loop() 开启消息循环。如下所示:

 new Thread("Thread#2"){            @Override            public void run() {                Looper.prepare();//为Thread#2 构建Looper,在该方法中,会将当前线程的Looper 存储在ThreadLocal 中                //为Thread#2 构建Handler,Handler 中会通过 mLooper = Looper.myLooper(); 获取当前线程的Looper                Handler handler = new Handler();                Looper.loop();//开启Looper 消息循环            }        }.start();

    Looper 还可通过prepareMainLooper 方法构建Looper,该方法主要是给主线程(ActivityThread) 创建Looper使用,其本质也是通过prepar 方法来实现的,由于主线程的Looper 比较特殊,故Looper 提供了一个 getMainLooper 方法,通过它可在任何地方获取到主线程的Looper。

Looper的退出:
1、通过quit 方法退出Looper,该方法会直接退出Looper
2、通过quitSafely 方法退出Looper,quitSafely  只是设定了一个退出标记,然后把消息队列中的已有的消息处理完毕后才安全的退出

        Looper 的 quit 和 quitSafely 方法:

    public void quit() {        mQueue.quit(false);    }    public void quitSafely() {        mQueue.quit(true);    }

        MessageQueue 的 quit 方法

    void quit(boolean safe) {        if (!mQuitAllowed) {            throw new IllegalStateException("Main thread not allowed to quit.");        }        synchronized (this) {            if (mQuitting) {                return;            }            mQuitting = true;//退出状态标志位            if (safe) {                removeAllFutureMessagesLocked();            } else {                removeAllMessagesLocked();            }            // We can assume mPtr != 0 because mQuitting was previously false.            nativeWake(mPtr);        }    }

    只有当Looper 的quit 或者quitSafely 方法被调用时,Looper 就会调用MessageQueue 的quit 方法来通知消息队列退出,当消息队列被标记为退出状态时,会跳出 next 方法的死循环并返回null,MessageQueue 的next 方法就会返回 null,就会跳出loop 方法的死循环。即Looper 必须退出,否则looper 方法会一直循环下去。

    Looper 退出后,通过Handler 发送的消息会失败,此时Handler 的send 方法会返回 false。在子线程中如果手动为其创建Looper,那么在所有的事情完成以后应该调用quit 方法来终止消息循环,否则这个子线程就会一直处于等待的状态,如果退出Looper 后,这个线程就会立刻被终止,因此建议不需要的时候终止Looper。

    Looper 最重要的一个方法是loop 方法,只有调用了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) {//如果消息为null, 即消息队列已退出,loop退出循环,                // 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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;            final long traceTag = me.mTraceTag;            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            final long end;            try {         //处理消息 msg.target 在Handler 的enqueueMessage 方法中被赋值为发送消息的handler对象,即调用handler 的dispatchMessage方法                msg.target.dispatchMessage(msg);                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            if (slowDispatchThresholdMs > 0) {                final long time = end - start;                if (time > slowDispatchThresholdMs) {                    Slog.w(TAG, "Dispatch took " + time + "ms on "                            + Thread.currentThread().getName() + ", h=" +                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);                }            }            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();        }    }

从上可知以下2点:
        loop 方法会调用 MessageQueue 的 next 方法来获取新的消息,当没有消息时,next 方法会阻塞在哪里,从而导致looper 方法阻塞在哪里,如果MessageQueue 的 next 方法返回了新消息,Looper 就会通过  msg.target.dispatchMessage(msg) 处理这条消息,这里的msg.target 是发送这条消息的 Handler 对象,这样 Handler 发送的消息最终又交给他的 dispatchMessage方法来处理了,但这里的 Handler 的dispatchMessage 方法是在创建 Handler 时 所使用的Looper 中执行的,这样就成功的将代码逻辑切换到指定的线程中去执行了

public final class Looper {    private static final String TAG = "Looper";    // sThreadLocal.get() will return null unless you've called prepare().    static final ThreadLocal sThreadLocal = new ThreadLocal();    private static Looper sMainLooper;  // guarded by Looper.class    final MessageQueue mQueue;    final Thread mThread;    private Printer mLogging;    public static void prepare() {        prepare(true);    }    //创建一个 Looper 对象,并存储在当前线程的ThreadLocal 中    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));    }    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }    /**     * Returns the application's main looper, which lives in the main thread of the application.     */    public static Looper getMainLooper() {        synchronized (Looper.class) {            return sMainLooper;        }    }    /**     * 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) {//当msg 为空时,退出                // 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 在Handler 的enqueueMessage 方法中被赋值为发送消息的handler对象,即调用handler 的dispatchMessage方法            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.recycleUnchecked();        }    }    /**     * Return the Looper object associated with the current thread.  Returns     * null if the calling thread is not associated with a Looper.     */    //从ThreadLocal 中获取当前线程存储的 Looper 对象    public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }    /**     * Return the {@link MessageQueue} object associated with the current     * thread.  This must be called from a thread running a Looper, or a     * NullPointerException will be thrown.     */    public static @NonNull MessageQueue myQueue() {        return myLooper().mQueue;    }    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);//创建一个 MessageQueue 消息队列        mThread = Thread.currentThread();//将当前的线程保存起来    }    /**     * Returns true if the current thread is this looper's thread.     */    public boolean isCurrentThread() {        return Thread.currentThread() == mThread;    }    /**     * Control logging of messages as they are processed by this Looper.  If     * enabled, a log message will be written to printer     * at the beginning and ending of each message dispatch, identifying the     * target Handler and message contents.     *     * @param printer A Printer object that will receive log messages, or     * null to disable message logging.     */    public void setMessageLogging(@Nullable Printer printer) {        mLogging = printer;    }    /**     * Quits the looper.     * 

* Causes the {@link #loop} method to terminate without processing any * more messages in the message queue. *

* Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. *

* Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. *

* * @see #quitSafely */ public void quit() { mQueue.quit(false); } /** * Quits the looper safely. *

* Causes the {@link #loop} method to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * However pending delayed messages with due times in the future will not be * delivered before the loop terminates. *

* Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. *

*/ public void quitSafely() { mQueue.quit(true); } /** * Gets the Thread associated with this Looper. * * @return The looper's thread. */ public @NonNull Thread getThread() { return mThread; } /** * Gets this looper's message queue. * * @return The looper's message queue. */ public @NonNull MessageQueue getQueue() { return mQueue; } /** * Dumps the state of the looper for debugging purposes. * * @param pw A printer to receive the contents of the dump. * @param prefix A prefix to prepend to each line which is printed. */ public void dump(@NonNull Printer pw, @NonNull String prefix) { pw.println(prefix + toString()); mQueue.dump(pw, prefix + " "); } @Override public String toString() { return "Looper (" + mThread.getName() + ", tid " + mThread.getId() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; }}

Handler 的工作原理:
        Handler 的主要工作包含消息的发送和接收过程。消息的发送可以通过post 的一些列方法及send 的一系列方法来实现,post 的一系列方法最终也是通过send 的一系列方法来实现的,发送一条消息的典型过程如下所示:

  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);    }   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) {        msg.target = this;//将发送消息的Handler 赋值给 msg.target        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);//调用 MessageQueue 的enqueueMessage 方法插入一条消息    }

        post 方法:

 public final boolean post(Runnable r)    {       return  sendMessageDelayed(getPostMessage(r), 0);    } private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;//将 Runnable 对象赋值给 m.callback        return m;    }

     从上可以发现,Handler 发送消息的过程仅仅是向消息队列中插入了一条消息,并将发送消息的Handler 赋值给 msg.target,MessageQueue 的next 方法就会返回这条消息给Looper,Looper 接收到消息后就开始处理了,最终消息由 Looper 交给 Handler 处理,即Handler 的 dispatchMessage 方法会被调用,这时 Handler就进入了处理消息的阶段,dispatchMessage  的实现如下所示:

    final Callback mCallback;    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

Handler 处理消息的过程如下:
        首先,检查Message 的 callback 是否为 null, 不为null 就通过 handlerCallback来处理消息,Message 的callback 是一个 Ruannable 对象,实际上就是 Handler 的post 方法所传递的 Runnable 参数, handlerCallback 的逻辑如下所示:

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

  其次检查mCallback 是否为 null,不null 就调用 mCallback 的 handlerMessage 方法来处理消息。Callback 是一个接口,其定义如下:

通过 Callback 可以通过如下方式来创建 Handler 对象:

        Handler handler = new Handler(callback);

    Callback  的意义就是可以用来创建一个Handler的实例但不需要派生Handler 的子类,在日常开发中,创建Handler 的最常见的方式就是派生一个Handler 的子类并重写其 handlerMessage 方法来处理具体的消息,当我们不想派生子类时,就可以通过Callback 来实现。最后调用Handler 的handleMessage 方法来处理消息。

   Handler 处理消息的过程可以归纳为一个流程图,如下所示:

Android 的消息机制之 Handler_第2张图片

        Handler 还有一个特殊的构造方法,可以通过一个特定的 Looper 来构造 Handler,它的实现如下:

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

        Handler 的默认构造方法如下:

    public Handler() {        this(null, false);    }    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 则会抛出"Can't create handler inside thread that has not called Looper.prepare()" 这个异常,即没有Looper在子线程中构建Handler 会报错的原因

 

        Handler 的完整源码如下:

public class Handler {    /*     * Set this flag to true to detect anonymous, local or member classes     * that extend this Handler class and that are not static. These kind     * of classes can potentially create leaks.     */    private static final boolean FIND_POTENTIAL_LEAKS = false;    private static final String TAG = "Handler";    /**     * 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);    }        /**     * Subclasses must implement this to receive messages.     */    public void handleMessage(Message 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);        }    }    /**     * 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;    }    /**     * Returns a string representing the name of the specified message.     * The default implementation will either return the class name of the     * message callback if any, or the hexadecimal representation of the     * message "what" field.     *       * @param message The message whose name is being queried      */    public String getMessageName(Message message) {        if (message.callback != null) {            return message.callback.getClass().getName();        }        return "0x" + Integer.toHexString(message.what);    }    /**     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).     *  If you don't want that facility, just call Message.obtain() instead.     */    public final Message obtainMessage()    {        return Message.obtain(this);    }    /**     * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.     *      * @param what Value to assign to the returned Message.what field.     * @return A Message from the global message pool.     */    public final Message obtainMessage(int what)    {        return Message.obtain(this, what);    }        /**     *      * Same as {@link #obtainMessage()}, except that it also sets the what and obj members      * of the returned Message.     *      * @param what Value to assign to the returned Message.what field.     * @param obj Value to assign to the returned Message.obj field.     * @return A Message from the global message pool.     */    public final Message obtainMessage(int what, Object obj)    {        return Message.obtain(this, what, obj);    }    /**     *      * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned     * Message.     * @param what Value to assign to the returned Message.what field.     * @param arg1 Value to assign to the returned Message.arg1 field.     * @param arg2 Value to assign to the returned Message.arg2 field.     * @return A Message from the global message pool.     */    public final Message obtainMessage(int what, int arg1, int arg2)    {        return Message.obtain(this, what, arg1, arg2);    }        /**     *      * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the      * returned Message.     * @param what Value to assign to the returned Message.what field.     * @param arg1 Value to assign to the returned Message.arg1 field.     * @param arg2 Value to assign to the returned Message.arg2 field.     * @param obj Value to assign to the returned Message.obj field.     * @return A Message from the global message pool.     */    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)    {        return Message.obtain(this, what, arg1, arg2, obj);    }    /**     * Causes the Runnable r to be added to the message queue.     * The runnable will be run on the thread to which this handler is      * attached.      *       * @param r The Runnable that will be executed.     *      * @return Returns true if the Runnable was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.     */    public final boolean post(Runnable r)    {       return  sendMessageDelayed(getPostMessage(r), 0);    }        /**     * Causes the Runnable r to be added to the message queue, to be run     * at a specific time given by uptimeMillis.     * The time-base is {@link android.os.SystemClock#uptimeMillis}.     * Time spent in deep sleep will add an additional delay to execution.     * The runnable will be run on the thread to which this handler is attached.     *     * @param r The Runnable that will be executed.     * @param uptimeMillis The absolute time at which the callback should run,     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.     *       * @return Returns true if the Runnable was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.  Note that a     *         result of true does not mean the Runnable will be processed -- if     *         the looper is quit before the delivery time of the message     *         occurs then the message will be dropped.     */    public final boolean postAtTime(Runnable r, long uptimeMillis)    {        return sendMessageAtTime(getPostMessage(r), uptimeMillis);    }        /**     * Causes the Runnable r to be added to the message queue, to be run     * at a specific time given by uptimeMillis.     * The time-base is {@link android.os.SystemClock#uptimeMillis}.     * Time spent in deep sleep will add an additional delay to execution.     * The runnable will be run on the thread to which this handler is attached.     *     * @param r The Runnable that will be executed.     * @param uptimeMillis The absolute time at which the callback should run,     *         using the {@link android.os.SystemClock#uptimeMillis} time-base.     *      * @return Returns true if the Runnable was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.  Note that a     *         result of true does not mean the Runnable will be processed -- if     *         the looper is quit before the delivery time of the message     *         occurs then the message will be dropped.     *              * @see android.os.SystemClock#uptimeMillis     */    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)    {        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);    }        /**     * Causes the Runnable r to be added to the message queue, to be run     * after the specified amount of time elapses.     * The runnable will be run on the thread to which this handler     * is attached.     * The time-base is {@link android.os.SystemClock#uptimeMillis}.     * Time spent in deep sleep will add an additional delay to execution.     *       * @param r The Runnable that will be executed.     * @param delayMillis The delay (in milliseconds) until the Runnable     *        will be executed.     *             * @return Returns true if the Runnable was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.  Note that a     *         result of true does not mean the Runnable will be processed --     *         if the looper is quit before the delivery time of the message     *         occurs then the message will be dropped.     */    public final boolean postDelayed(Runnable r, long delayMillis)    {        return sendMessageDelayed(getPostMessage(r), delayMillis);    }        /**     * Posts a message to an object that implements Runnable.     * Causes the Runnable r to executed on the next iteration through the     * message queue. The runnable will be run on the thread to which this     * handler is attached.     * This method is only for use in very special circumstances -- it     * can easily starve the message queue, cause ordering problems, or have     * other unexpected side-effects.     *       * @param r The Runnable that will be executed.     *      * @return Returns true if the message was successfully placed in to the      *         message queue.  Returns false on failure, usually because the     *         looper processing the message queue is exiting.     */    public final boolean postAtFrontOfQueue(Runnable r)    {        return sendMessageAtFrontOfQueue(getPostMessage(r));    }    /**     * Runs the specified task synchronously.     * 

* If the current thread is the same as the handler thread, then the runnable * runs immediately without being enqueued. Otherwise, posts the runnable * to the handler and waits for it to complete before returning. *

* This method is dangerous! Improper use can result in deadlocks. * Never call this method while any locks are held or use it in a * possibly re-entrant manner. *

* This method is occasionally useful in situations where a background thread * must synchronously await completion of a task that must run on the * handler's thread. However, this problem is often a symptom of bad design. * Consider improving the design (if possible) before resorting to this method. *

* One example of where you might want to use this method is when you just * set up a Handler thread and need to perform some initialization steps on * it before continuing execution. *

* If timeout occurs then this method returns false but the runnable * will remain posted on the handler and may already be in progress or * complete at a later time. *

* When using this method, be sure to use {@link Looper#quitSafely} when * quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely. * (TODO: We should fix this by making MessageQueue aware of blocking runnables.) *

* * @param r The Runnable that will be executed synchronously. * @param timeout The timeout in milliseconds, or 0 to wait indefinitely. * * @return Returns true if the Runnable was successfully executed. * Returns false on failure, usually because the * looper processing the message queue is exiting. * * @hide This method is prone to abuse and should probably not be in the API. * If we ever do make it part of the API, we might want to rename it to something * less funny like runUnsafe(). */ public final boolean runWithScissors(final Runnable r, long timeout) { if (r == null) { throw new IllegalArgumentException("runnable must not be null"); } if (timeout < 0) { throw new IllegalArgumentException("timeout must be non-negative"); } if (Looper.myLooper() == mLooper) { r.run(); return true; } BlockingRunnable br = new BlockingRunnable(r); return br.postAndWait(this, timeout); } /** * Remove any pending posts of Runnable r that are in the message queue. */ public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } /** * Remove any pending posts of Runnable r with Object * token that are in the message queue. If token is null, * all callbacks will be removed. */ public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); } /** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Sends a Message containing only the what value. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } /** * Sends a Message containing only the what value, to be delivered * after the specified amount of time elapses. * @see #sendMessageDelayed(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } /** * Sends a Message containing only the what value, to be delivered * at a specific time. * @see #sendMessageAtTime(android.os.Message, long) * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } /** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) uptimeMillis. * The time-base is {@link android.os.SystemClock#uptimeMillis}. * Time spent in deep sleep will add an additional delay to execution. * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ 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); } /** * Enqueue a message at the front of the message queue, to be processed on * the next iteration of the message loop. You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * This method is only for use in very special circumstances -- it * can easily starve the message queue, cause ordering problems, or have * other unexpected side-effects. * * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ 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); } /** * Remove any pending posts of messages with code 'what' that are in the * message queue. */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } /** * Remove any pending posts of messages with code 'what' and whose obj is * 'object' that are in the message queue. If object is null, * all messages will be removed. */ public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } /** * Remove any pending posts of callbacks and sent messages whose * obj is token. If token is null, * all callbacks and messages will be removed. */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); } /** * Check if there are any pending posts of messages with code 'what' in * the message queue. */ public final boolean hasMessages(int what) { return mQueue.hasMessages(this, what, null); } /** * Check if there are any pending posts of messages with code 'what' and * whose obj is 'object' in the message queue. */ public final boolean hasMessages(int what, Object object) { return mQueue.hasMessages(this, what, object); } /** * Check if there are any pending posts of messages with callback r in * the message queue. * * @hide */ public final boolean hasCallbacks(Runnable r) { return mQueue.hasMessages(this, r, null); } // if we can get rid of this method, the handler need not remember its loop // we could instead export a getMessageQueue() method... public final Looper getLooper() { return mLooper; } public final void dump(Printer pw, String prefix) { pw.println(prefix + this + " @ " + SystemClock.uptimeMillis()); if (mLooper == null) { pw.println(prefix + "looper uninitialized"); } else { mLooper.dump(pw, prefix + " "); } } @Override public String toString() { return "Handler (" + getClass().getName() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; } private static void handleCallback(Message message) { message.callback.run(); } final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; private static final class BlockingRunnable implements Runnable { private final Runnable mTask; private boolean mDone; public BlockingRunnable(Runnable task) { mTask = task; } @Override public void run() { try { mTask.run(); } finally { synchronized (this) { mDone = true; notifyAll(); } } } public boolean postAndWait(Handler handler, long timeout) { if (!handler.post(this)) { return false; } synchronized (this) { if (timeout > 0) { final long expirationTime = SystemClock.uptimeMillis() + timeout; while (!mDone) { long delay = expirationTime - SystemClock.uptimeMillis(); if (delay <= 0) { return false; // timeout } try { wait(delay); } catch (InterruptedException ex) { } } } else { while (!mDone) { try { wait(); } catch (InterruptedException ex) { } } } } return true; } }}

主线程的消息循环:
        Android 的主线程就是ActivityThread,主线程的入口方法为 main,在main 方法中系统会通过 Looper.preparMainLooper() 来创建主线程的Looper 记忆MessageQueue,并通过Looper.loop() 来开启主线程的消息循环,过程如下所示:

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

    主线程的消息循环开始以后,ActivityThread 还需要一个Handler来和消息队列进行交互,这个Handler 就是ActivityThread.H,它的内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程,如下所示:

 private class H extends Handler {        public static final int LAUNCH_ACTIVITY         = 100;        public static final int PAUSE_ACTIVITY          = 101;        public static final int PAUSE_ACTIVITY_FINISHING= 102;        public static final int STOP_ACTIVITY_SHOW      = 103;        public static final int STOP_ACTIVITY_HIDE      = 104;        public static final int SHOW_WINDOW             = 105;        public static final int HIDE_WINDOW             = 106;        public static final int RESUME_ACTIVITY         = 107;        public static final int SEND_RESULT             = 108;        public static final int DESTROY_ACTIVITY        = 109;        public static final int BIND_APPLICATION        = 110;        public static final int EXIT_APPLICATION        = 111;        public static final int NEW_INTENT              = 112;        public static final int RECEIVER                = 113;        public static final int CREATE_SERVICE          = 114;        public static final int SERVICE_ARGS            = 115;        public static final int STOP_SERVICE            = 116;        ... }

     ActivityThread 通过 ApplicationThread 和AMS 进行进程间通信,AMS 以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 中的Binder 方法,然后 ApplicationThread 会向 H 发送消息,H收到消息后会将ApplicationThread 中的逻辑切换到 ActivityThread 中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。

总结:
   1、创建Handler 时,会优先检查是否有Looper,如果没有则抛出异常,由于主线程即ActivityThread 在创建时就构建了Looper(通过Looper.prepareMainLooper 构建),所以在主线程中构建Handler 不会抛异常,如果在子线程中,在构建Handler 之前必须先创建Looper (通过Looper.preparLooper 创建),创建好Handler 后,还需启动Looper。
    2、构建Looper 时,会创建一个 MessageQueue ,并将该Looper 存储在当前线程的 ThreadLocal 中,通过 Looper.looper 开启轮询,不停的查找 MessageQueue 中的消息,如果存在未处理的消息,则通过 Message 中的 tag 获取关联的 Handler,并调用 Handler.dispatchMessage 方法处理消息,该方法会最终调用 handlerMessage 方法或者Runable 中 的方法处理消息。
    3、Handler 通过 sendMessage 或者 post 方法发送消息,首先会将自己赋值给 Message 的tag,并调用MessageQueue 中的enqueueMessage 方法向MessageQueue 中插入一条消息,Looper 通过MessageQueue 的next 方法获取MessageQueue 中的消息,获取后并将之从 MessageQueue 中删除,如果 MessageQueue 中没有消息,则MessageQueue 、Looper 都会被阻塞挂起。

更多相关文章

  1. android中使用httpclient方法获得网页内容并对json对象解析
  2. Handler消息传送机制总结
  3. Android Studio3.0开发JNI流程------在Android原程序添加自己类
  4. 利用Android的Matrix类实现J2ME的drawRegion的镜像方法
  5. Android线程通信机制-Handler(Java层)
  6. [原]Android应用程序线程消息循环模型分析
  7. Systrace 分析性能工具使用方法详解

随机推荐

  1. Android 三种sendBroadCast的方式对比
  2. pc上安装anroid系统
  3. Android进程启动
  4. android防止service多次执行onStartComma
  5. android应用框架搭建------工具类(StringU
  6. eclipse 开发 android源码
  7. Android入门第一篇layout,onclicklisente
  8. Android HTTPS实战2
  9. Android软键盘弹出
  10. Android APK加壳技术