Android 的消息机制之 Handler
首先明白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所在的线程中的
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 处理消息的过程可以归纳为一个流程图,如下所示:
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 都会被阻塞挂起。
更多相关文章
- android中使用httpclient方法获得网页内容并对json对象解析
- Handler消息传送机制总结
- Android Studio3.0开发JNI流程------在Android原程序添加自己类
- 利用Android的Matrix类实现J2ME的drawRegion的镜像方法
- Android线程通信机制-Handler(Java层)
- [原]Android应用程序线程消息循环模型分析
- Systrace 分析性能工具使用方法详解