1. Android消息机制相关类
- Message:硬件产生的消息(按钮、触摸)和软件生成的消息
- MessageQueue:消息队列,向消息池推送消息和取出消息
- Handler:消息处理辅助类,用于发送消息和处理消息
- Looper:线程运行消息循环类,默认情况下线程没有与之关联的消息循环,可以调用prepare(),然后调用loop()使之处理消息。如果一个Looper开始工作后,一直没有消息处理的话,那么该线程就会被阻塞。在非UI线程中,这时候应该监听当前MessageQueue的Idle事件,如果当前有Idle事件,则应该退出当前的消息循环,然后结束该线程,释放相应的资源。
1.1 相关类图
Handler消息机制类图2. Looper
looper主要方法就是looper.prepare()和looper.loop()
2.1 Loopr.prepare()
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//prepare方法只能执行一次
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//向线程本地存储区TLS保存新创建的Looper
sThreadLocal.set(new Looper(quitAllowed));
}
ThreadLocal
线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。
ThreadLocal内部结构图: ThreadLocal结构ThreadLocal机制:
- 每个线程内部都有一个ThreadLocalMap
- ThreadLocalMap中存储的是Entry,其key是ThreadLocal的弱引用,value是线程变量副本,且这个value的值的类型是ThreadLocal的泛型类型(key是弱引用而value不是,注意内存泄漏)
ThreadLocal.get()
public T get() {
Thread t = Thread.currentThread();
//获取线程内部的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
//根据TheadLocal对象获取Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//返回null
return setInitialValue();
}
ThreadLocal.set()
public void set(T value) {
Thread t = Thread.currentThread();
//获取线程内部的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//ThreadLocalMap的set方法,采用的不是map存储而是entry对象存储,
//使用的是线性探测解决hash冲突,详见ThreadLocalMap.set()
map.set(this, value);
else
//初始化线程内部的ThreadLocalMap
createMap(t, value);
}
2.2 Looper.loop()
public static void loop() {
//获取当前线程的Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取Looper关联的MessageQueue
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.
//清楚IPC身份标志
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
//从MessageQueue中获取一个Message,如果当前MessageQueue没有消息,就会阻塞;
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//调用Message中的Handler分发消息
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();
//IPC 身份标识发生变化
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();
}
}
3. MessageQueue
使用单链表的方式维护一个消息队列,提高频繁插入删除消息等操作的性能,该链表用消息的when字段进行排序,先被处理的消息排在链表前部。内部的阻塞轮询和唤醒等操作,使用JNI来实现。
主要方法enqueueMessage()和next()
3.1 MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
//message中的handler不能为null
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);
//回收message
msg.recycle();
return false;
}
//标识正在使用
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//当前msg时间与队首时间对比,小于则放队首
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.
//阻塞,队首是barrier并且msg是异步
needWake = mBlocked && p.target == null && msg.isAsynchronous();
//以下代码找到合适位置插入msg
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
//msg前面有异步消息不唤醒
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.
//唤醒调用native方法
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
3.1 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;
}
//Idle时间标记成第一次
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) {
//首部为barrier消息,则取出最头的异步消息
// 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.
//到执行时间取走msg
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 {
//执行idlehandler
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;
}
}
4. Message
消息对象,内部包含一个单链表实现的最大数量为50的消息池,以避免频繁创建对象带来的开销,主要方法有obtain()和recycleUnchecked()
4.1 Message.obtain()
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();
}
4.2 Message.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++;
}
}
}
5. Handler
负责消息的发送和接收,主要方法enqueueMessage()和dispatchMessage()
5.1 Handler.enqueueMessage()
Handler.sendEmptyMessage()等最终都是调用enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//msg持有handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//调用MessageQueue的enqueueMessage方法
return queue.enqueueMessage(msg, uptimeMillis);
}
5.2 Handler.dispatchMessage()
/**
* 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);
}
}
消息分发流程:
Message的callback-->Handler的mCallback-->Handler的handleMessage
6. 总结
Handler消息机制流程- Handler通过sendMessage()发送Message到MessageQueue
- Message到MessageQueue后唤醒loop线程,MessageQueue中没有Message则执行IdleHnalder接口中方法
- Looper通过loop()方法不断取出Message,并将Message交给其target(Handler)处理
网友评论