这篇笔记主要参考了如下博客的文章:web
Android Handler机制
Android 消息机制之MessageQueueshell
为何使用Handler?数组
ANR
,新版本的Android系统中,若是在主线程中进行耗时操做,还会抛出异常。所以须要将耗时操做放在子线程中进行。Handler
将须要更新UI的操做包装成一个Message
发送到主线程,而后在主线程中进行更新UI的操做。在上面的描述中,涉及到一些问题,以下:安全
Handler
,若是子线程不用操做UI,那么就不须要Handler
,子线程执行完任务结束就能够了。 综上所示,Handler
通常用于多线程中,将工做线程中须要更新UI的操做信息传递到主线程中,从而实现工做线程对UI的更新处理,最终实现异步消息的处理。使用Handler
的目的,也是为了在多个线程并发更新UI的同时,保证线程安全。bash
和Handler
相关的概念主要包括Handler
,Message
,Message Queue
,Looper
,相关概念以下:网络
概念 | 定义 | 做用 | 备注 |
主线程 | 当应用程序第一次启动的时候,会同时自动开启一条主线程 | 处理和UI相关的事件 | 主线程和子线程通讯的媒介=Handler |
子线程 | 人为手动开启的线程 | 执行耗时操做(如网络请求等) | 与主线程经过Handler通讯 |
Message | 线程间通讯的数据单元 | 存储需操做的通讯信息 | 通常在子线程中建立 |
Message Queue | 一种数据结构(先进先出) | 存储Handler发送过来的消息 | 存在于主线程中 |
处理者(Handler) | 主线程与子线程通讯的媒介,线程消息的主要处理者 | 添加消息(Message)到消息队列(Message Queue); 处理循环器(Lopper)分派过来的消息(Message) |
/ |
循环器(Looper) | 消息队列(Message Queue)与处理者(Handler)的通讯媒介 | 负责消息循环,也就是: 1.消息获取:循环取出消息队列(Message Queue)的消息(Message); 2.消息分发:将取出的消息(Message)发送给对应的处理者(Handler) |
Handler
的使用方式因发送消息到消息队列的方式不一样而不一样,共分为两种:数据结构
Handler.sendMessage(Message)
Handler.post(Runnable)
Handler
机制的工做流程主要包括四个步骤:多线程
具体以下表所示:并发
步骤 | 具体描述 | 备注 |
1.异步通讯准备 | 在主线程中建立: |
|
2.消息入队 | 工做线程(子线程)经过Handler发送消息(Message)到消息队列(Message Queue)中 | 该消息内容 = 工做线程对UI的操做 |
3.消息循环 | |
在消息循环过程当中,若消息队列为空,则线程阻塞 |
4.消息处理 | |
/ |
Handler
的工做流程以下图所示:app
Handler
的工做流程示意图以下图所示:
Handler
机制中有三个重要的类,分别是:
Handler
)Message Queue
)Looper
)三个重要类的类图以下所示:
三个重要的类的具体介绍以下图所示:
至此,咱们已经了解了Handler
的基本运行机制:
当一个应用启动的时候,会同时建立一个主线程或称为UI线程,在这个线程中会同同时建立Message Queue
和Looper
。当咱们须要在子线程中进行某一项工做,而且工做完成以后须要操做UI的时候,咱们会建立一个Handler
用于接收子线程操做UI的信息。
执行完上面的操做以后,咱们一般会开启一个子线程,为了可以操做UI,咱们须要将上一步建立的Handler
对象传递到子线程中,当子线程执行完操做以后,会将须要操做UI的信息包装成一个Message
对象,经过Handler.sendMessage()
方法将Message
添加到Message Queue
中。
因为Looper
是一个死循环,当有消息进入到Message Queue
中的时候,会当即从其中取出消息,而后就开始分发消息开始执行。这样就完成了从子线程向主线程中传递消息的操做。
可是到这里,仍然有几个问题须要解决:
Looper
和Message Queue
?如何建立?Looper
如何自动进入消息循环体中?Handler
如何实现和Looper
和Message Queue
的自动绑定?Message
传递消息的时候有什么限制? Handler
发送消息分为两种方式,分别是Handler.sendMessage()
和Handler.post()
,下面根据不一样方式进行源码分析:
1.使用步骤
//建立Handler
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
mBinding.tvResult.setText(msg.obj.toString());
}
}
};
//建立消息对象
Message message = Message.obtain();
message.what = 0;
message.obj = this.getClass().getSimpleName();
//在子线程中发送消息
mThreadHandler.sendMessage(message);
//这里的子线程我经过继承Thread实现
class TestThread extends Thread{
private Handler mThreadHandler;
TestThread(Handler handler){
this.mThreadHandler = handler;
}
@Override
public void run() {
super.run();
Message message = Message.obtain();
message.what = 0;
message.obj = this.getClass().getSimpleName();
mThreadHandler.sendMessage(message);
}
}
复制代码
在上面的示例中,经过匿名内部类的方式建立了Handler
对象,首先会执行Handler
无参的构造方法,源码以下:
public Handler() {
this(null, false);
}
复制代码
能够看到,在无参的构造方法中,调用了Handler(callback:null,async: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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
复制代码
在上面的源码中,首先咱们须要判断FIND_POTENTIAL_LEAKS
的值是否为true
,这是一个静态变量,默认为false
,从名字上也能够理解,这个变量就是用来标记是否要发现隐藏的内存泄露。
那么若是这个值为true
,它的判断方法为:
getClass()
获取到这个类运行时真实的Class
信息isAnonymousClass()
,isMemberClass()
,isLocalClass()
判断这个类是不是匿名类(就像 new OnClickListener()这种就是匿名类,上面定义Handler的时候也是用的是匿名类),或者是不是成员类(定义在类中类),亦或者是不是局部类(定义在方法中的类)。kclass.getModifiers() & Modifirt.STATIC
来查看当前类是否使用static
修饰(getModifiers()
能够获取到类的修饰符,使用整数表示,Modifier.STATIC
的二进制数为1000
,作与运算,只有getModifiers()
返回的整数的二进制数的最高位为1
,最后的结果才不会为0)。Looper.myLooper()
绑定当前线程的Looper
,而后判断,若是Looper
为空则会抛出异常。 Looper.myLooper()
方法的源码以下:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
复制代码
Looper
中的sThreadLocal
定义以下:
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 复制代码
从注释也能够看出,只有调用了prepare()
方法以后,sThreadLocal.get()
才不会返回null
。
查看Looper
中的源码也能够发现,Looper
只有一个private
的构造方法,也就是说,Looper
只能经过prepare()
方法进行初始化,源码以下:
//Looper构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//prepare()方法
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(); } } 复制代码
从上面的源码能够看出,Looper
的主要做用就是将当前线程初始化为循环线程,经过prepareMainLooper()
方法能够将当前线程标记为应用程序的主循环程序,主循环程序是由Android环境建立的,本身建立的话可使用prepare()
函数。
由此,咱们能够得出如下结论:
Looper
中的prepareMainLooper()
方法将当前线程标记为一个不能够退出的主循环程序。ThreadLocal sThreadLocal
的get()
方法是否为空来使得一个线程中只能有一个Looper
,若是sThreadLocal.get()
方法返回空,那么就经过Looper
的private
的构造方法建立一个Looper
,并将建立的对象设置给sThreadLocal
中的ThreadLocalMap
进行保存。Looper
的构造方法的时候会建立MessageQueue
的对象,此时就已经建立好了Looper
和MessageQueue
了。Handler
进行子线程向主线程传递数据的时候,咱们就能够直接在主线程中建立Handler
,而后在Handler
的构造方法当中设置当前线程的Looper
和MessageQueue
对象。而后将Handler
的实例传递给子线程(在外部建立的子线程须要经过这种方式),这样在子线程中的数据处理完成以后咱们就就能够调用Handler
的方法向MessageQueue
中添加Message
了。下面是Android APP启动时的部分源码:
public static void main(String[] args) {
... // 仅贴出关键代码
Looper.prepareMainLooper();
// 1. 为主线程建立1个Looper对象,同时生成1个消息队列对象(MessageQueue)
// 方法逻辑相似Looper.prepare()
// 注:prepare():为子线程中建立1个Looper对象
ActivityThread thread = new ActivityThread();
// 2. 建立主线程
Looper.loop();
// 3. 自动开启 消息循环 ->>下面将详细分析
}
复制代码
经过上面的分析,咱们已经清楚了当APP启动的时候,系统会帮咱们自动建立一个主线程,同时生成Looper
和MessageQueue
对象,有了这两个对象以后,Looper
就能够调用loop()
方法进行消息循环了,下面是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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
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;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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(); } } 复制代码
在上面的方法中,首先会判断当前线程的Looper
对象是否存在,不存在则会抛出异常。也就是说在执行loop()
前必须执行prepare()
方法,为此线程建立Looper
,不然会抛出异常。
接下来的两行代码经过注释能够知道,是确保此线程的身份是本地进程的身份,并跟踪该身份令牌的实际含义,这两行代码的实际意义并非很懂,须要后面解决。
接下来是一个for
循环,在for
循环中,首先经过queue.next()
方法获取一个Message
对象,注释中也说明了这个方法可能会阻塞。若是这个Message
为空,那么就会跳出循环。若是这个Message
不为空,那么就会执行msg.target.diapatchMessage(msg)
方法,将这个Message
分发给对应的Handler
去处理。以后调用msg.recycleUnchecked()
方法释放msg
。
MessageQueue
中获取Message
的操做 经过上面的源码能够发现,Looper
中是经过MessageQueue
中的next()
方法来获取下一个须要操做的Message
,下面是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;
}
}
复制代码
上面的注释已经说明:若是消息循环已经退出而且被释放,那么就直接返回null
,这种状况通常发生在应用程序在退出后仍然尝试从新启动不受支持的循环。结合代码中ptr == 0
的时候返回null
能够知道,当ptr == 0
的时候表示消息循环已经退出而且被释放掉了。 mPtr
的做用是保存 native
层的MessageQueue
的引用地址。
接着定义pendingIdleHandlerCount = -1;
表示空闲事件处理IdleHandler
的数量为-1
,即尚未处理过任何的IdleHandler
。而后定义nextPollTimeoutMillis = 0
。
接着一样进入一个for
死循环,这时会调用nativePollOnce(ptr, nextPollTimeoutMillis);
,这个方法额的主要做用是设置线程等待多久以后唤醒,时间由nextPollTimeoutMillis
来指定。
接下来进入到同步方法中,正式开始获取Message
。具体操做步骤以下:
MessageQueue
中的第一个Message
对象,也就是mMessages
,若是mMessages
不为空,而且mMessages
的target
属性为null
则进入以下循环:do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
复制代码
在上面的循环中,能够看出,就是从第二个Message
开始获取,若是获取到的Message
不为空而且不是异步操做的Message
则继续循环,也就是说,这个循环条件是获取到第一个是异步操做的Message
或者循环完成则跳出循环。
在这里,首先要解释一下Message
的三种状态,分别是:
Message
的target
的属性为空Message
时候设置为同步属性Message
时设置为异步属性 同步和异步属性的差距主要在于障栈会阻碍同步Message
的执行,而不会阻碍异步Message
的执行,这里并不意味着异步的Message
会在异步线程执行。
MessageQueue
中的代码中,通过第一步的运行,咱们拿到的Message
多是如下状况:MessageQueue
中已经没有待处理的Message
,或者障栈以后没有异步的Message
Message
,MessageQueue
中的第一个Message
不是障栈,那次是这里就是第一个Message
Message
,MessageQueue
中的第一个Message
时障栈,而且在以后的Message
中找到了第一个异步的Message
。接着进入到下面的判断中:
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;
}
}
复制代码
在上面的源码中,首先判断获取的Message
是否为空,不为空则继续执行以下的操做:
Message
的执行时间(经过now
和msg.when
)进行判断,若是没有到达当前线程的执行时间,则设置线程须要阻塞的时间,这个时间最大为int
的最大值。Message
执行的时间,那么就设置mBlocked = false
,也就是不须要阻塞,而后判断prevMsg
是否为空,不为空则说明当前MessageQueue
的第一个Message
是障栈,此时prevMsg
是障栈以后第一个异步Message
以前的msg
,这样将prevMsg
的next
指向当前Message
的下一个Message
便可。若是prevMsg
为空,那么就直接设置MessageQueue
的第一个Message
为当前Message
的下一个Message
便可。而后设置当前Message
的next
为空,这样就将当前的Message
从MessageQueue
中脱离出来了。而后标记当前的Message
正在使用中,并返回。Message
为空,设置nextPollTimeoutMillis = -1;
表示没有更多的Message
了。Message
须要处理,或者当前的Message
尚未到执行时间的话,会查看是否有退出的消息须要处理,若是有,就执行退出的消息:// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
复制代码
从上面的dispose()
方法中也能够看出,当MessageQueue
退出以后,mPtr
的值会被设置为0,表示当前MessageQueue
已经退出。
MessageQueue
不须要退出,那么判断当前MessageQueue
是不是第一次空闲,判断的依据是pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)
,pendingIdleHandlerCount
的初始赋值为-1
,而且MessageQueue
中没有要处理的Message
,或者当前要处理的Message
的时间尚未到,那么此时就获取须要处理的IdleHandler
的数量.代码以下:if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
endingIdleHandlerCount = mIdleHandlers.size();
}
复制代码
IdleHandler
,若是没有则设置须要阻塞(由于程序执行到这里,说明已经没有待处理的Message
,或者当前须要处理的Message
的时间还没到,因此线程须要阻塞,等待下一个事件到来),而后跳出循环,开始执行下一次循环。代码以下:if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
复制代码
IdleHandlers
数组是否为空,为空则会建立一个数组,数组的最大值为须要处理的IdleHandler
的数量和4
中较大的一个。而后将存放须要处理的IdleHandler
的列表中的数据复制到数组中。if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
复制代码
IdleHandler
来执行其中的操做,具体代码以下: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);
}
}
}
复制代码
能够看到具体的执行过程也是每次从数组中取出一个IdleHandler
,而后执行其中的queueIdle()
方法,最后执行完成后根据返回的结果,若是执行完成后不须要继续将这个IdleHandler
保持起来,那么就从列表中移除它,不然不移除。
pendingIdleHandlerCount
和nextPollTimeoutMillis
的值。 设置pendingIdleHandlerCount = 0
主要是为了保证IdleHandler
只会执行一次。而之因此要设置nextPollTimeoutMillis = 0
是为了防止在执行IdleHandler
的时候添加了新的信息,这样是为了可以当即再次查找MessageQueue
中的Message
(之因此须要这样是由于在上面获取Message
的时候,须要执行的那个Message
的时间尚未到,因此咱们在那里设置了须要等待的时间,也就是对nextPollTimeoutMillis
进行了赋值,可是后面执行IdleHandler
时须要时间的,若是这里不设置nextPollTimeoutMillis = 0
,那么下次循环的时候就会调用nativePollOnce(ptr, nextPollTimeoutMillis);
方法设置阻塞的时间,这样的话,一旦在咱们执行IdleHandler
的时候有新的须要当即执行的Message
插入进来而没有重置nextPollTimeoutMillis = 0
,那么下次循环的时候仍是按照以前设置的时间阻塞,那么新加进来的Message
就无法当即执行。)。
Looper
中的loop()
方法 前面已经了解了loop()
方法的大致流程,下面再进入到其中的循环中查看代码:
MessageQueue
的next()
方法获取须要执行的Message
,若是获取到的Message
为空,则结束循环:for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
···其它代码···
复制代码
经过上面的MessageQueue
中的代码,咱们已经了解了,在MessageQueue
中的next()
方法中,只有MessageQueue
已经退出才会返回null
,可是咱们以前也了解过,主线程中建立的MessageQueue
是不容许退出的,也就是说正常状况下,主线程中的MessageQueue
的next()
方法是不会返回null
的,从而说明Looper
中的loop()
方法中的for()
循环在正常状况下不会退出。
try...catch
中执行的操做,在这里会将Message
分发给具体的Handler
去进行处理,代码以下:try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag); }
}
复制代码
Message
:msg.recycleUnchecked();
复制代码