Android 源码解析- Handler 实现机制
2017-09-11 09:37
399 查看
源码是Android API 25
Handler 、 Looper 、Message 这三者到底有什么样的关系?什么叫异步消息处理线程呢?本文将在源码层面进行分析。
Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能出现ANR。解决的方法是创建一个Message对象,然后通过Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了。
Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例,应用程序的主线程不断地从这个消息队例中获取消息,然后对这些消息进行处理,这样就实现了通过消息来驱动应用程序的执行。这样做的好处就是消息的发送方只要把消息发送到应用程序的消息队列中去就行了,它可以马上返回去处理别的事情,而不需要等待消息的接收方去处理完这个消息才返回,这样就可以提高系统的并发性。实质上,这就是一种异步处理机制。An
4000
droid应用程序的消息处理机制也是由消息循环、消息发送和消息处理这三个部分组成的,接下来,我们就详细解析这三个过程。
ActivityThread.java main 方法的代码如下:
该函数首先创建了 一个 ActivityThread 实例, 然后通过Looper 类使得应用进入消息循环中,如果 Looper 中出错,就会抛出 “Main thread loop unexpectedly exited” ,下面我么来分析Looper 是如何让应用进入消息循环的, Looper 类位于frameworks/base/core/java/android/os/Looper.java 文件中。
首先我们分析 prepareMainLooper 方法,该方法主要是在线程中创建一个给sMainLooper 初始化,Looper 类中有一个类型为ThreadLoacal 的成员变量 sThreadLocal , 保证每一个线程中有一个独立的Looper对象,线程中创建Looper 是通过prepare()方法完成的。 Looper 中有一个类型为MessageQueue的成员变量mQueue, 消息就是存在这个变量中的, MessageQueue 是实现消息循环的重要部分, 下面我们来解析MessageQueue 的源码, 源码位于 rameworks/base/core/java/android/os/MessageQueue.java 文件中。
构造方法是本地实现的 , JNI 层主要实现的功能是创建一个消息队列NativeMessageQueue , 并且在JNI 层创建一个Looper 对象,把JNI 层的NativeMessageQueue 消息对象保存到Java 层中创建的MessageQueue对象的mPtr成员变量中,JNI 层Looper 的部分代码如下
主要是创建了一个管道, 该部分与应用程序主线程在消息队列中没有消息时要进入等待状态以及当消息队列有消息时要把应用程序主线程唤醒相关, 上面的部分主要做了如下三件事,
第一 、在Java层创建一个Looper对象,它的内部有一个消息队列MessageQueue对象mQueue
第二、在JNI层创建一个NativeMessageQueue对象,这个NativeMessageQueue对象保存在Java层的消息队列对象mQueue的成员变量mPtr中;
第三、在C++层创建一个Looper对象,保存在JNI层的NativeMessageQueue对象的成员变量mLooper中,这个对象的作用是,当Java层的消息队列中没有消息时,就使Android应用程序主线程进入等待状态,而当Java层的消息队列中来了新的消息后,就唤醒Android应用程序的主线程来处理这个消息。上面的工作准备好之后,ActivitThread 函数中的main 方法中调用Looper 中的loop() 方法 代码如下:
通过该方法就进入到消息循环中了,不断的读取mQueue 中的消息msg , 如果msg 为null for 循环结束,如果不为空调用,msg.target.dispatchMessage(msg) 来处理消息。该函数最关键的部分是Message msg = queue.next(); // might block ,即MessageQueue.next函数,方法的代码如下:
有两种情况会使线程进入等待状态,一种是消息队列中没有消息,一种是消息队列中有消息但是没有到指定的执行时间, 执行nativePollOnce(ptr, nextPollTimeoutMillis); 看看当前消息队列中有没有消息。该方法中有两个参数,一个是ptr,指向的是JNI 层创建的NativeMessageQueue, nextPollTimeoutMillis表示等待的时间, 开始的时候传入的是0 表示不等待。该方法返回后,就去检查消息队列中有无消息,该函数来检测消息队列中有无消息, 关键代码如下:
如果消息队列中有消息,并且大于消息中的执行时间,直接返回msg 处理,否则的话就要等待到消息的执行时间:等待是的时长为nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);如果无消息 nextPollTimeoutMillis = -1 就会无限的等待。。。
上面部分已经将消息的循环部分讲完了 , 下面要分析的是消息的发送。
callBackHandler.sendMessage函数把这个消息对象msg加入到应用程序的消息队列中去,然后通 handleMessage 方法来处理消息
下面我们来分析下Handler 的构造方法
mLooper 与Queue 是构造方法中最重要的成名变量, myLooper 是一个静态方法,通过该方法可以获取到一个Looper 对象,如果获取到对象为空,说明还没有调用Loopepr.prepare() 方法。通过Looper 对象可以获取到mQeue 对象。进而可以通过Looper.mQueue来访问应用程序的消息队列。
下面我我们来分析如何将消息发送到消息队列的, 首先分析的是handler 的sendMessage(Message msg) 方法
msg.target = this , 这么目标由谁来处理,这里赋值为this, 表示这个消息最终由这个Handler 来处理,消息发送最关键的一个函数是 queue.enqueueMessage(msg, uptimeMillis); 源代码如下
将消息加入到消息队列时,有两种情况, 第一种是消息队列为空,只需要把消息加入到消息队列头即可,
第二种是消息队列中有消息,并且我们发送的消息指定了消息的发送时间,这个时候需要需要根据发送的时间进行排序。核心代码如下:
消息按照排序时间排好之后就会调用 nativeWake(mPtr); 该函数的主要操作是唤醒主线程来处理消息。这个时候就会返回到Java层中的MessageQueue.next函数,主线程开始处理消息。
到这里消息的发送已经分析完了。下面分析消息的处理。
msg 不为null 时,就会调用它的target成员变量的dispatchMessage函数来处理这个消息,这个消息对象msg的成员变量target是在发送消息的时候设置好的,一般就通过哪个Handler来发送消息,就通过哪个Handler来处理消息。
我们发消息的时候可以是一下几种方法
Handler 中的 dispatchMessage 方法如下:
这里的消息对象msg的callback成员变量和Handler类的mCallBack成员变量一般都为null,于是,就会调用Handler类的handleMessage函数来处理这个消息
分析到这里已经把Handler 分析完了 。
Handler 、 Looper 、Message 这三者到底有什么样的关系?什么叫异步消息处理线程呢?本文将在源码层面进行分析。
Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能出现ANR。解决的方法是创建一个Message对象,然后通过Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了。
Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例,应用程序的主线程不断地从这个消息队例中获取消息,然后对这些消息进行处理,这样就实现了通过消息来驱动应用程序的执行。这样做的好处就是消息的发送方只要把消息发送到应用程序的消息队列中去就行了,它可以马上返回去处理别的事情,而不需要等待消息的接收方去处理完这个消息才返回,这样就可以提高系统的并发性。实质上,这就是一种异步处理机制。An
4000
droid应用程序的消息处理机制也是由消息循环、消息发送和消息处理这三个部分组成的,接下来,我们就详细解析这三个过程。
1、 消息循环
应用程序的主线程是围绕消息队列进入一个无线循环的,如果消息队列中有消息,主线程会把它取出来并交给相应的Handler 进行处理, 在消息队列没有消息的情况下,主线程会进入空想等待状态, 直到下一个消息的到来。Android 应用程序中的的消息循环是通过Looper 类来实现的,Looper.java 位于 frameworks/base/core/java/android/os/Looper.java 中, 接下来我们分析下Android 应用程序是如何进入消息循环的。我们都知道,应用程序启动时会在进程中加载ActiityThread类,从类的main 函数开始执行,下面我们来解析ActivityThread 类, 该类位于frameworks/base/core/java/android/app 目录下。ActivityThread.java main 方法的代码如下:
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("<pre-initialized>"); 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 实例, 然后通过Looper 类使得应用进入消息循环中,如果 Looper 中出错,就会抛出 “Main thread loop unexpectedly exited” ,下面我么来分析Looper 是如何让应用进入消息循环的, Looper 类位于frameworks/base/core/java/android/os/Looper.java 文件中。
public final class Looper { /* * API Implementation Note: * * This class contains the code required to set up and manage an event loop * based on MessageQueue. APIs that affect the state of the queue should be * defined on MessageQueue or Handler rather than on Looper itself. For example, * idle handlers and sync barriers are defined on the queue whereas preparing the * thread, looping, and quitting are defined on the looper. */ private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; private Printer mLogging; private long mTraceTag; /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { prepare(true); } 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)); } /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ 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) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a 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); 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 <var>printer</var> * 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; } /** {@hide} */ public void setTraceTag(long traceTag) { mTraceTag = traceTag; } /** * Quits the looper. * <p> * Causes the {@link #loop} method to terminate without processing any * more messages in the message queue. * </p><p> * 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. * </p><p class="note"> * 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. * </p> * * @see #quitSafely */ public void quit() { mQueue.quit(false); } /** * Quits the looper safely. * <p> * 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. * </p><p> * 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. * </p> */ public void quitSafely() { mQueue.quit(true); } /** * Gets the Thread 14942 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)) + "}"; } }
首先我们分析 prepareMainLooper 方法,该方法主要是在线程中创建一个给sMainLooper 初始化,Looper 类中有一个类型为ThreadLoacal 的成员变量 sThreadLocal , 保证每一个线程中有一个独立的Looper对象,线程中创建Looper 是通过prepare()方法完成的。 Looper 中有一个类型为MessageQueue的成员变量mQueue, 消息就是存在这个变量中的, MessageQueue 是实现消息循环的重要部分, 下面我们来解析MessageQueue 的源码, 源码位于 rameworks/base/core/java/android/os/MessageQueue.java 文件中。
...... private native static long nativeInit(); ....... MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
构造方法是本地实现的 , JNI 层主要实现的功能是创建一个消息队列NativeMessageQueue , 并且在JNI 层创建一个Looper 对象,把JNI 层的NativeMessageQueue 消息对象保存到Java 层中创建的MessageQueue对象的mPtr成员变量中,JNI 层Looper 的部分代码如下
int wakeFds[2]; int result = pipe(wakeFds); ...... mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1];
主要是创建了一个管道, 该部分与应用程序主线程在消息队列中没有消息时要进入等待状态以及当消息队列有消息时要把应用程序主线程唤醒相关, 上面的部分主要做了如下三件事,
第一 、在Java层创建一个Looper对象,它的内部有一个消息队列MessageQueue对象mQueue
第二、在JNI层创建一个NativeMessageQueue对象,这个NativeMessageQueue对象保存在Java层的消息队列对象mQueue的成员变量mPtr中;
第三、在C++层创建一个Looper对象,保存在JNI层的NativeMessageQueue对象的成员变量mLooper中,这个对象的作用是,当Java层的消息队列中没有消息时,就使Android应用程序主线程进入等待状态,而当Java层的消息队列中来了新的消息后,就唤醒Android应用程序的主线程来处理这个消息。上面的工作准备好之后,ActivitThread 函数中的main 方法中调用Looper 中的loop() 方法 代码如下:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
通过该方法就进入到消息循环中了,不断的读取mQueue 中的消息msg , 如果msg 为null for 循环结束,如果不为空调用,msg.target.dispatchMessage(msg) 来处理消息。该函数最关键的部分是Message msg = queue.next(); // might block ,即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) { 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; } }
有两种情况会使线程进入等待状态,一种是消息队列中没有消息,一种是消息队列中有消息但是没有到指定的执行时间, 执行nativePollOnce(ptr, nextPollTimeoutMillis); 看看当前消息队列中有没有消息。该方法中有两个参数,一个是ptr,指向的是JNI 层创建的NativeMessageQueue, nextPollTimeoutMillis表示等待的时间, 开始的时候传入的是0 表示不等待。该方法返回后,就去检查消息队列中有无消息,该函数来检测消息队列中有无消息, 关键代码如下:
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; }
如果消息队列中有消息,并且大于消息中的执行时间,直接返回msg 处理,否则的话就要等待到消息的执行时间:等待是的时长为nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);如果无消息 nextPollTimeoutMillis = -1 就会无限的等待。。。
上面部分已经将消息的循环部分讲完了 , 下面要分析的是消息的发送。
2、消息发送
消息发送的代码如下:Handler callBackHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return false; } }); Message msg = Message.obtain(); msg.what = 1; callBackHandler.sendMessage(msg);
callBackHandler.sendMessage函数把这个消息对象msg加入到应用程序的消息队列中去,然后通 handleMessage 方法来处理消息
下面我们来分析下Handler 的构造方法
public Handler(Callback callback, boolean async) { 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; }
mLooper 与Queue 是构造方法中最重要的成名变量, myLooper 是一个静态方法,通过该方法可以获取到一个Looper 对象,如果获取到对象为空,说明还没有调用Loopepr.prepare() 方法。通过Looper 对象可以获取到mQeue 对象。进而可以通过Looper.mQueue来访问应用程序的消息队列。
下面我我们来分析如何将消息发送到消息队列的, 首先分析的是handler 的sendMessage(Message msg) 方法
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; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
msg.target = this , 这么目标由谁来处理,这里赋值为this, 表示这个消息最终由这个Handler 来处理,消息发送最关键的一个函数是 queue.enqueueMessage(msg, uptimeMillis); 源代码如下
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; }
将消息加入到消息队列时,有两种情况, 第一种是消息队列为空,只需要把消息加入到消息队列头即可,
if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; }
第二种是消息队列中有消息,并且我们发送的消息指定了消息的发送时间,这个时候需要需要根据发送的时间进行排序。核心代码如下:
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;
消息按照排序时间排好之后就会调用 nativeWake(mPtr); 该函数的主要操作是唤醒主线程来处理消息。这个时候就会返回到Java层中的MessageQueue.next函数,主线程开始处理消息。
到这里消息的发送已经分析完了。下面分析消息的处理。
3、消息处理
消息的处理是在Looper 的loop() 中开始的代码如下:public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } msg.recycleUnchecked(); } }
msg 不为null 时,就会调用它的target成员变量的dispatchMessage函数来处理这个消息,这个消息对象msg的成员变量target是在发送消息的时候设置好的,一般就通过哪个Handler来发送消息,就通过哪个Handler来处理消息。
我们发消息的时候可以是一下几种方法
Handler callBackHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { // 使用Handler 的Callback 方法 return false; } }); Handler overrideHandler = new Handler() { @Override public void handleMessage(Message msg) { //重写handleMessage方法 super.handleMessage(msg); } }; Message message = Message.obtain(callBackHandler, new Runnable() { @Override public void run() { // 传入Runnable 参数 } }); }
Handler 中的 dispatchMessage 方法如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); //优先是Message 中的Callback } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { //其次是handler 中的Callback return; } } handleMessage(msg); //最后是重写的方法 } } private static void handleCallback(Message message) { message.callback.run(); } public interface Callback { public boolean handleMessage(Message msg); }
这里的消息对象msg的callback成员变量和Handler类的mCallBack成员变量一般都为null,于是,就会调用Handler类的handleMessage函数来处理这个消息
分析到这里已经把Handler 分析完了 。
相关文章推荐
- 基础篇-Android异步机制,AsynaTask源码解析与Handler对比
- Android消息机制Handler源码简单解析
- Android消息机制Handler的实现原理解析
- 带你从源码看Android Handler 异步消息处理机制完全解析
- Android多线程消息处理机制(四) Message、MessageQueue源码解析和Handler综合使用
- Android HandlerThread 消息循环机制之源码解析
- Android 源码解析Handler处理机制(二)
- Android源码:Handler, Looper和MessageQueue实现解析
- 从源码来一步一步解析Android中Handler消息机制
- android的消息处理惩罚机制(图+源码解析)——Looper,Handler,Message
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android消息机制源码解析(二)——消息的执行者Handler
- Android源码解析Handler系列第(三)篇---深入了解Android的消息机制
- Android Handler消息机制源码解析(上)
- Android消息处理机制:源码剖析Handler、Looper,并实现图片异步加载
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- 深入理解Android消息机制,从源码解析Handler,Looper,MessageQueue
- 【 Android】handler异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- Android Handler 异步消息处理机制二:源码解析,深入理解Looper、Handler、Message三者关系