Handler详解(上)
https://blog.csdn.net/weixin_37730482/article/details/72864047
本章节讲解Handler的源码分析。
一.发送消息 源码分析
上节讲到,Handler的几个常用的发送消息的方法,最后都会不约而同的走到sendMessageAtTime(Message msg, long uptimeMillis)方法。那么我们的消息发送源码之旅就在这个方法开始吧。
常用方法调用关系流程图
源码之Handler类
sendMessageAtTime()方法源码
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* 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(@NonNull 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);
}
该方法主要有两个工作
(1) 赋值MessageQueue对象。
(2) 调用本类的enqueueMessage()方法。enqueueMessage()方法稍后再看。
先看一下MessageQueue的赋值。
MessageQueue queue = mQueue;
那么这个mQueue对象是哪里来的呢?他又是在哪里赋值的呢?
final MessageQueue mQueue;
可见mQueue对象是Handler类的全局变量。哪里赋值的?源码发现Handler类里有两个地方赋值这个变量。
赋值处1
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());
}
}
//获取Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//赋值MessageQueue对象
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
赋值处2
public Handler(Looper looper, Callback callback, boolean async) {
//赋值Looper对象
mLooper = looper;
//赋值MessageQueue对象
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
也就是说上述sendMessageAtTime()方法中的MessageQueue对象的赋值变量mQueue。是在Handler的构造方法里赋值的。Handler的构造方法了除了赋值MessageQueue对象还赋值了Looper对象。可是明明刚刚简单使用时创建Handler的时候,我用的是一个参数的构造方法。没有使用源码中两个参数和三个参数的构造方法呀。其实Handler的构造方法在Handler内部是互相调用的。如下。因为构造方法比较多。这里我们就列举两个和MessageQueue+Looper有关的构造方法。
无参构造方法 也就是上述 简单使用中的举例
public Handler() {
this(null, false);
}
内部调用 本类的两个参数构造方法。也就是 赋值处1 。不过要注意的是使用无参构造方法时。Looper对象因为没有传参,所以需要获取。
mLooper = Looper.myLooper();
如何获取,下面讲解。
接着看一个参数的构造方法。也就是上述 使用postDelayed方法在子线程延时更新UI的举例
public Handler(Looper looper) {
this(looper, null, false);
}
内部调用 本类的三个参数的构造方法。也就是赋值处2 。因为Looper对象已通过参数传参,左移这里无需获取,直接使用传入的参数即可。
到这里,通过Handler的构造方法也可以看出。Handler是离不开MessageQueue和Looper的。
小结1
<1> sendMessageAtTime()方法中核心代码就两行。首先会赋值MessageQueue对象。
<2> 创建Handler时,可以使用的构造方法很多,如果没有传参Looper对象。则构造方法里默认获取(怎么获取下面讲)。如果传参Looper对象。则使用传参的Looper对象。
<3> 创建Handler时,使用Looper对象,获取MessageQueue对象。
源码之Looper类
上面说到,在创建Handler对象时,如果没有传入Looper对象,系统会自己取Looper对象。那么Looper是怎么获取的呢?
mLooper = Looper.myLooper();
也就是,通过Looper的myLooper()方法。
myLooper()方法源码
/**
* 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();
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
很明显,myLooper()方法是通过ThreadLocal的get方法获取的Looper对象。sThreadLocal变量是Looper类的全局变量。因为既然可以使用sThreadLocal.get()方法获取Looper对象。那么什么时候set的呢?因为只有set了值,才可以get到值。
sThreadLocal变量set值是在prepare()方法中。
prepare()方法源码
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//sThreadLocal变量set值
sTreadLocal.set(new Looper(quitAllowed));
}
注意:prepare()方法中 sThreadLocal变量set值时 首先会先get值,如果get值不为空,也就是说已经创建过Looper。会抛出异常。Only one Looper may be created per thread。也就是说一个线程只能有一个Looper对象。这也是面试的重点。
prepare()方法是在哪里调用的呢?
调用处1
public static void prepare() {
prepare(true);
}
这个prepare()方法就是通过代码手动调用Looper.prepare()时。比如 子线程创建Handler对象
//来给线程创建一个消息循环
Looper.prepare();
//来使消息循环起作用。
Looper.loop();
调用处2
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepareMainLooper()方法是在哪里调用的呢?
public static void main(String[] args) {
//调用prepareMainLooper()方法
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
}
也就是在ActivityThread类的main方法中调用的。而ActivityThread类是APP运行时,默认为APP创建的主线程。
注意刚刚 sThreadLocal变量set值时创建Looper对象
sThreadLocal.set(new Looper(quitAllowed));
也就是说,Looper的创建时机是在Looper类的prepare()方法中调用的。而上述也讲了。prepare()方法有两个地方调用。
1.主线程ActivityThread类中的main()方法系统默认调用。
2.子线程手动调用Looper.prepare();方法调用。
在创建Looper时,做了两件事。
1.创建MessageQueue对象。
2.将当前线程赋值给mThread对象。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
注意,Looper的构造方法中创建MessageQueue时,传了一个布尔值。quitAllowed。
而由上述源码可知。
ActivityThred类的main()方法调用Looper.prepareMainLooper();时传参是false。
而手动调用Looper.prepare();时传参是true。
那么这个参数有什么作用呢?
此参数当成参数传到MessageQueue的构造方法中
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
此变量什么时候使用
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
...
}
也就是,如果这个参数是false。则不让退出Looper循环。根据抛出的异常也可以看出Main thread not allowed to quit.。也就是说主线程默认开始的Looper是不允许退出的。
小结2
<1> 发送消息,最后走到Handler类的sendMessageAtTime方法。而该方法需要赋值一个MessageQueue对象。而MessageQueue对象是要Looper对象获取。
<2> Looper对象获取有两个途径。
(1) 使用Handler时,如果传Looper对象。则Looper对象就用传过来的参数即可。
(2) 使用Handler时,如果没有传Looper对象。则需要系统自己获取。
<3> 系统获取Looper对象,最终通过ThreadLocal对象的get方法获取。ThreadLocal对象set的时机有两个。
(1) ActivityThread类的main方法默认给APP创建主线程时调用Looper类的prepareMainLooper()方法。
(2) 手动调用Looper类的Looper.prepare();方法 自己准备Looper对象。
<4> ThreadLocal对象set设置Looper对象时会创建Looper对象。创建Looper对象时会做两件事情。
(1) 创建MessageQueue对象。
(2) 获取当前线程给全局的Looper类的全局线程变量。
<5> 创建Looper时,有一个布尔类型的参数。此参数主线程默认创建调用时传的是false。而手动调用创建Looper时传的是true。这个参数又会当成参数在Looper构造方法中创建MessageQueue时,传给MessageQueue类。此布尔值在MessageQueue中的作用就是是否允许退出Looper循环。而上述也讲解过了。由于主线程传递的是false。所以主线程是不允许退出Looper循环的。
<6> sThreadLocal.set(new Looper(quitAllowed));时,会先get值,如果get的值不为空,会抛出异常。也就是说一个线程只允许一个Looper存在。
源码之Handler类
下面接着sendMessageAtTime()方法 继续讲解
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
MessageQueue的赋值已经讲解清楚了。下面看enqueueMessage()方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
首先,将this对象赋值给Message的target。那么this代表什么呢?在Handler类里面this当然代表的Handler。也就是发送Message时使用的Handler对象。
最后调用MessageQueue类的enqueueMessage()方法。显然,enqueueMessage()方法是MessageQueue对象调用的。也就是说走到这里已经脱离了Handler类。而到了MessageQueue类。
小结3
<1> 发送消息 在Handler类里的最后一个方法是enqueueMessage方法。
<2> Handler类的enqueueMessage方法中,赋值Message对象的target属性为this。也就是说到这里 每个发出去的Message都持有把它发出去的Handler的引用。而Message又存放到MessageQueue中,如果需要延时可能在MessageQueue中的位置还可能靠后。这就是使用Handler时如果使用不当可能造成内存泄漏的原因。
源码之MessageQueue类
消息发送 从Handler类的enqueueMessage方法 最后走到 MessageQueue类的enqueueMessage()方法 走到这里相当于 消息入消息队列(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;
}
方法中,如果Message的target为空,或者正在被使用直接抛出异常。继续
同步代码块中 如果正在退出,将Message回收,然后return false。结束。否则 继续
mMessage是消息队列中的第一条消息。
//消息在使用状态
msg.markInUse();
//消息延时时间
msg.when = when;
//消息队列中的头部消息mMessages赋值给p
Message p = mMessages;
大致的意思就是:将传进来要发送的消息对象变成在使用状态+传进来的延时时间赋值给传进来的消息。然后将头部消息赋值给p。
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
}
如果头部消息为空 或者 当前传参的消息延时时间为零 或者 当前传参的消息延时时间比头部消息延时时间小,将传进来的消息放到头部。
else {
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;
}
否则 For循环中就是当前消息队列不为空,或者 当前传参消息延时时间比头部消息延时时间大,将参数的Message对象插入消息队列中等待执行。插入位置和延时时间相关。
小结4
<1> 消息发送 走到MessageQueue类的enqueueMessage()方法。相当于入消息队列(MessageQueue其实是一个单链表)。
<2> 传进来要发送的消息在MessageQueue中位置,与其延时时间以及队列中是否有其他消息有关。
源码之Message类
Message类部分源码
public final class Message implements Parcelable {
...
Handler target;
Runnable callback;
Message next;
...
}
也就是说,Message类其实是一个实现了Parcelable接口的实体类。上述Handler类的enqueueMessage()方法发送消息时将Handler的对象赋值给Message的target对象,其实就是赋值给Message类中的Handler变量。通俗一点将就是 每个发出去的Message对象都会持有Handler对象的引用。这也就是使用Handler时容易造成内存泄漏的原因。具体原因下一章节讲解。
注意
创建Message的方式。在使用Handler进行线程通讯时,必不可少的要创建Message,而为了内存优化在创建Message时,最好不要new一个Message。
正确的写法
Message msg = Message.obtain();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";
正确的写法
Message msg = handler.obtainMessage();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";
备注
handler.obtainMessage();内部调用了Message.obtain();
如下
/**
* 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.
*/
@NonNull
public final Message obtainMessage(){
return Message.obtain(this);
}
错误的写法
Message msg = new Message();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";
即,创建Message使用Message的缓存池。
Message的obtain()方法源码
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//全局静态消息对象,相当于消息池
private static Message sPool;
//消息池中的消息数量 Message.obtain()执行 此数-1 表示消息池中有一个消息被重复使用 Looper.loop取消息时,会清空使用过的消息 此数+1 表示消息池中又多了一个可以被重复使用的消息 具体+1操作 消息接收模块讲解
private static int sPoolSize = 0;
//消息池中的消息最大个数 具体使用 消息接收模块讲解
private static final int MAX_POOL_SIZE = 50;
大致可以这样理解。通过Message缓存池方式获取Message对象时,首先判断缓存池中有没有Message,如果有就直接取出使用,然后消息池中可被重复使用的消息个数-1。如果没有这时才new一个Message。默认消息池消息数量为50。
到这里消息发送就讲解完了。那么发送的消息是怎么到达消息接收的地方呢?下面继续讲解
二.消息接收 源码分析
上面讲到了消息发送最终会走到MessageQueue类的enqueueMessage(Message msg, long when)方法。按照消息队列中是否有消息和当前消息延时时间,将传进来的消息对象插到消息队列的相应位置。那么 发送的消息 怎么到 消息接收 的方法呢?
比如 postDelayed方法 怎么到run()方法呢?
handler.postDelayed(new Runnable() {
@Override
public void run() {
}
},500);
比如 匿名内部类创建Handler 怎么到handleMessage()方法呢?
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
答案就在Looper类的loop()方法。那我们的消息接收源码之旅就在这个方法开始吧。
源码之Looper类
loop()方法源码
public static void loop() {
//核心代码1处 获取Looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
//核心代码2处 使用Looper对象获取MessageQueue对象
final MessageQueue queue = me.mQueue;
final long ident = Binder.clearCallingIdentity();
boolean slowDeliveryDetected = false;
for (;;) {
//核心代码3处 使用MessageQueue的next()方法获取Message对象。
Message msg = queue.next(); // might block
//核心代码4处 如果MessageQueue中取出的Message对象为空 则退出无限循环。
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final Observer observer = sObserver;
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;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
//核心代码5处 msg.target就是发送消息的时候传入的Handler对象,即发送消息的Handler
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//核心代码6处 调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中
msg.recycleUnchecked();
}
}
此方法,按照标记有六处要点。
<1> 获取Looper对象。上面已经讲过,这里就不赘述了
//核心代码1处 获取Looper对象
final Looper me = myLooper();
<2> 使用Looper对象获取MessageQueue对象
//核心代码2处 使用Looper对象获取MessageQueue对象
final MessageQueue queue = me.mQueue;
<3> 在For循环(无限循环)中用MessageQueue的next方法取出MessageQueue中的Message对象 MessageQueue的next()方法还是挺复杂的下面讲解
//核心代码3处 使用MessageQueue对象获取Message对象。
Message msg = queue.next(); // might block
<4> 如果从MessageQueue中取出的Message对象为空,也就是说消息队列中暂时没有消息了。则退出For循环(无限循环)
//核心代码4处 如果MessageQueue中取出的Message对象为空 则退出无限循环。
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
<5> 调用Handler的dispatchMessage()方法发布消息
//核心代码4处 msg.target就是发送消息的时候传入的Handler对象,即发送消息的Handler
msg.target.dispatchMessage(msg);
此处的msg.target就是发送消息时的Handler对象。上面已经讲过,这里就不赘述了
<6> 该方法的最后调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中。
//核心代码5处 调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中
msg.recycleUnchecked();
小结1
<1> Looper类的loop()方法,里面有一个For循环(无限循环)。用来循环的取出MessageQueue中的Message。当从MessageQueue中取出的Message为空时,即消息队列暂时没有消息时,会退出For循环(无限循环)。
<2> Looper类的loop()方法走到最后,就到了Handler类的dispatchMessage()方法。来做消息发布。也就是说Looper类的loop方法,是用来循环取出MessageQueue中的Message的。而真正的消息发布走的是Handler类的dispatchMessage()方法。
<3> Looper类的loop()方法哪里调用呢?前面也讲过了
(1) 主动调用 APP默认的主线程ActivityThread类的main方法中调用。
Looper.prepareMainLooper();
(2) 子线程手动调用
Looper.loop();
源码之MessageQueue类
上述Looper类的loop()方法取出MessageQueue中的Message时,调用了MessageQueue类的next方法。
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;
}
}
MessageQueue类的next方法,源码比较多。而且里面好多native的方法。这里就不赘述了,主要看Java层的代码。大致的意思就是取出MessageQueue中的消息。因为发送消息入队列时是按照Message的延时时间确定的位置。那么取出MessageQueue中的Message时也是一样。按照延时时间取。即取出延时时间较短(入消息队列时放在前面的消息)。
小结2
取出MessageQueue中的消息时,用的是next()方法。根据延时时间,取出急需发送的消息。
源码之Message类
上述Looper类的loop()方法 最后一行 消息发出后 调用了Message类的recycleUnchecked()方法。
recycleUnchecked()方法源码
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
小结3
<1> Looper类的loop()方法发布消息后。会执行Message类的recycleUnchecked()方法。
<2> 该方法就是回收消息,将消息变成可被重复使用的消息,然后放到消息池中。
<3> 具体的回收就是 将Message的flags置成可使用状态 将Message的what属性 arg1属性 arg2属性 obj属性 when属性 target属性等等都置成默认初始的值。然后如果当前消息池中的消息数量小于MAX_POOL_SIZE即小于50。将当前消息赋值给消息池对象sPool 然后消息池中可被重复使用的消息数+1。
源码之Handler类
上述Looper类的loop()方法,最后的消息发布是执行的Handler类的dispatchMessage()方法。
dispatchMessage()方法源码
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
此方法,有两个重点。
<1> 如果Message的callback对象不为空。执行handleCallback(msg);方法。
那么Message的callback对象是啥呢
Runnable callback;
即,使用post方法或者postDelayed方法传参的Runnable对象。如下。
handler.postDelayed(new Runnable() {
@Override
public void run() {
}
},500);
然后handleCallback(msg);实际是
private static void handleCallback(Message message) {
message.callback.run();
}
即,调用Runnable对象的run方法。此时上述postDelayed方法的run()方法就会执行了。
<2> 否则如果mCallback不为空 则
if (mCallback.handleMessage(msg)) {
return;
}
mCallback对象是哪里来的呢 是在Handler的构造方法中传过来的
mCallback = callback;
此种方式的回调
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
即 这个mCallback是创建Handler的时候可以选择传一个CallBack回调,里面依然是handleMessage方法。 调用自己接口的回调方法,一般不使用。
<3> 前两种情况都不满足走到下面的方法
handleMessage(msg);
public void handleMessage(@NonNull Message msg) {
}
即。一般创建Handler的时候重写的handleMessgae()方法。
小结4
消息发送,从Looper类的loop()方法到Handler类的dispatchMessage()方法。完成了消息的发布。
到这里消息接收就讲解完了。消息发送&消息接收。全部的源码就基本讲述完成。
附:Handler+Message+MessageQueue+Looper图表