对线程中消息队列(MessageQueue)进行循环获取到Message,然后对Message进行分发处理,在Handler中调用Callback或handleMessage()来处理事件
Thread在默认情况下(主线程除外,主线程在程序启动时就已经创建了Looper对象)并没有与它关联的Looper,所以在handler对象生成之前需要调用Looper.prepare()来创建与线程关联的Looper对象,在线程中任务开始执行时,调用Looper.loop()来循环对应线程中的消息,
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// do something()
}
};
Looper.loop();
}
public static void main(String[] args) {
Looper.prepareMainLooper();
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {// 每个线程中都只有一个Looper,如果重复调用该函数就会抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
初始化Looper时,创建MessageQueue,同时获取与该Looper对象对应的线程
public static void loop() {
final Looper me = myLooper();// 获取当前线程对应的Looper对象
if (me == null) { // 该线程没有初始化Looper
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取指定线程中Looper的消息队列
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// 消息队列中没有消息队列已经调用了quit函数.
return;
}
// 调用handler的dispatchMessage()对消息进行处理
msg.target.dispatchMessage(msg);
// 回收消息,将消息内部数据置为空
msg.recycleUnchecked();
}
}
注意:
MessageQueue.quit();
void quit(boolean safe) {
if (safe) {
removeAllFutureMessagesLocked();// 清空MessageQueue消息池中所有的延迟消息(通过postDelay()...发送的消息)并将消息池中所有的非延迟消息派发出去让Handler去处理
} else {
removeAllMessagesLocked();// 清空MessageQueue中的所有消息
}
}
}
quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息,调用quit之后,Looper就不再接收新的消息,因为消息队列已经退出了.
ActivityThread.java
中,在退出程序时会调用主线程中Looper.quit()
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
通过上述介绍,我们可以知道:
ThreadLocal
为每一个使用该变量的线程提供一个变量值的副本,是java中一种较为特殊的线程绑定机制,即:每一个线程都可以独立的改变自己的副本,而不会和其他线程的副本发生冲突.在ThreadLocal中有一个Map,用于存储每一个线程的变量副本.其中,key为当前线程,value为数据,不同的线程的key是不同的,所以它们之间的数据不会发生错误.
保存线程通信时用到的消息,对消息进行插入,获取,移除回收操作;
我们一般说他是消息队列包含所有的消息,但是实际上它只包含一个Message,而在每Message中有一个Message对象next,就这样每个Message都有一个next指向下一个Message对象,从而形成了一条数据链.
MessageQueue是通过enqueueMessage()和next()来执行Message的插入和取出
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
// mPtr是从android_os_MessageQueue_nativeInit返回的MessageQueue的地址
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
return 0;// MessageQueue初始化失败
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
boolean enqueueMessage(Message msg, long when) {
// 1.判断消息是否可用
// 2.开始循环MessageQueue中的消息,将Message插入到对应的位置
synchronized (this) {
if (mQuitting) {// 该消息队列已结束循环,Message插入失败,回收message
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//将Message插入到MessageQueue队列的头部
msg.next = p;
mMessages = msg;
needWake = mBlocked;// 如果阻塞,则需要唤醒.
} else {
//通过循环找出msg在队列中的位置(按照时间顺序(从小到大)),然后将Message插入到队列中对应的位置
// 判断是否需要唤醒队列:如果队列阻塞,头部消息是Barrier并且插入的消息是异步消息则有可能需要唤
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
// p.next = msg,判断是否需要唤醒:消息队列中有异步消息并且执行时间在新消息之前,所以不需要唤醒。
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}// 将数据插入到数据链中
msg.next = p;
prev.next = msg;
}
// 如果需要唤醒Looper,调用nativeWake取消阻塞
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
从上面我们可以看出
```java
Message next() {
//消息队列已不存在
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int nextPollTimeoutMillis = 0; // 阻塞时长
for (;;) {
//阻塞操作,等待唤醒或者等待nextPollTimeoutMillis时长
nativePollOnce(ptr, nextPollTimeoutMillis);// 阻塞操作
synchronized (this) {// 同步操作为了数据安全和准确性
// uptimeMillis用来判断时间(不受系统时间影响).
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 这种情况是队列中当前消息是barrier类型的,寻找队列中下一条的异步消息
// Barrier同步障碍消息(用来阻塞队列的),异步消息不受该消息的影响,
// postSyncBarrier():向MessageQueue中添加同步障碍消息
// removeSyncBarrier():移除消息队列中对应的障碍消息;
do {
// 获取异步或null Message
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) { // 该消息处于阻塞状态
// 设置消息阻塞时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else { // 处于唤醒状态
// 将得到的next Message
return msg;
}
} else {
// 队列中没有消息
nextPollTimeoutMillis = -1;
}
// 结束消息循环,清空消息队列,释放内存
if (mQuitting) {
dispose();
return null;
}
}
}
Barrier: 它也是一种Message,在next()
函数中就有简单介绍
消息的target为null就表示它是个Barrier,在MessageQueue中,有两种向消息队列中添加消息的函数,一种是enqueueMessage,另一种是enqueueBarrier,而enqueueMessage中如果mst.target为null是直接抛异常的,这个在源码中可以看到.
通过enqueueBarrier往消息队列中插入一个BarrierMessage,队列中消息执行时,在这个Barrier以后的同步消息都会被这个Barrier拦截阻塞住无法执行,直到我们调用removeBarrier移除了这个Barrier,或者异步消息. 因为异步消息不受它的影响,可以继续执行.
removeCallbacksAndMessages(Handler h, Object object)
removeMessages(Handler h, Runnable r, Object object)
移除消息队列的Message,我们通过调用handler.remove()来调用它们.
boolean hasMessages()
判断消息队列是否含有指定消息
原文:Callback interface for discovering when a thread is going to block waiting for more messages
MessageQueue中的message处理完了或者是需要阻塞等待一段时间,这个时候会回调这个接口
作用:就是在线程中的消息处理完或消息处于阻塞时调用该函数.这时,我们就可以做一些我们自己需要的操作了.
调用该接口时,如果该函数返回false,那么就会把它从消息队列的mIdleHandlers中移除,返回true就会在下次继续回调
public void addIdleHandler(@NonNull IdleHandler handler)
向消息队列中添加IdleHandler对象
public void removeIdleHandler(@NonNull IdleHandler handler)
从消息队列中移除IdleHandler对象
该函数在源码中的调用
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
for (;;) {
synchronized (this) {
if (pendingIdleHandlerCount <= 0) {
// 没有IdleHandler,继续循环
continue;
}
}
// 循环调用MessageQueue中的mIdleHandlers,
for (int i = 0; i < pendingIdleHandlerCount; i++) {
try {
keep = idler.queueIdle();
} catch (Throwable t) {
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
}
}
我们可以看到:在调用next()函数之后,我们先循环获取消息,如果队列中的消息为null或者是处于阻塞时,才会调用上面这段代码来循环mIdleHandlers,如果mIdleHandlers中含有数据,就会执行IdleHandler中的queueIdle()函数,最后判断是否需要从mIdleHandlers中移除IdleHandler对象
在源码ActivityThread中就使用到了IdleHandler ,通过下面代码我们可以更加直观的了解IdleHandler.
final class GcIdler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
doGcIfNeeded();
return false;
}
}
void scheduleGcIdler() {
if (!mGcIdlerScheduled) {
mGcIdlerScheduled = true;
Looper.myQueue().addIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
void unscheduleGcIdler() {
if (mGcIdlerScheduled) {
mGcIdlerScheduled = false;
Looper.myQueue().removeIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
该类中最重要的只有两个函数,就生成(obtain),回收(recycler),
生成
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();
}
它主要是从Message对象池中取出一个Message对象
其他obtain()都是基于该函数,只是指定了Message的一些属性而已
回收
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++;
}
}
}
该函数把Message内的数据置为初始状态,然后存储对象池中
发送消息
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}// 通过looper获取到messagequeue,然后调用messagequeue.enqueueMessage()将Message插入到队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
接受消息
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
try {
msg.target.dispatchMessage(msg);
}
msg.recycleUnchecked();
}
}
通过Looper.loop不断循环调用MessageQueue.next()获取队列头部的消息Message,因为message包含Handler对象,所以通过message.target.dispatchMessage(msg)来分发消息.
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
该函数判断消息中是否含有Runnable,如果有则执行handleCallback(msg);否则,如果handler中含有Callback 接口对象的话,就调用Callback.handleMessage(),handler没有callback对象的话则调用handler.handleMessage()来处理Message
private static void handleCallback(Message message) {
message.callback.run();
}
他实际上是回调Runnable的run()函数.
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
这个是我们在创建handler时,需要传入的接口对象,回调时使用
我们在多线程消息接收处理中使用最多的就是这种模式了
消息移除
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
在MessageQueue中,循环把队列中的全部消息都通过recycleUnchecked()回收到Message的对象回收池中.
他们的具体不同之处可以看源码了解
创建一个Handler对象,它和正常Handler对象的区别就是它发布的Message或Runnable不会受到同步栅栏消息的阻塞
同步栅栏消息只阻塞同步消息.