Handler 基础了解
1. Handler 是干嘛的
说白了,Handler 就是 Android 提供的 线程之间交互 的一种方式,并在系统层面同样大量使用。
2. Handler 的工作流程是怎样的
当每个线程创建时,可选择 为该线程创建自己的循环队列 (Looper + MessageQueue) ,当 [线程B] 想发送消息给 [线程A] 时,只需要在 [线程B] 把消息推送到 [线程A] 的 MessageQueue 中,[线程A] 就可以用 Looper 提取 MessageQueue 中的 Message 了
3. 系统有哪些地方使用了 Handler
- CountDownTimer
- Messenger
- AsyncTask
- IntentService
- View
- LocalBroadcast
- 等
4. Handler 机制所使用的主要类
- Message
- MessageQueue
- Looper
- Handler
5. Handler 的基础使用方法
// 1.在需要接受数据的线程创建Handler
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// 4.这里接收发送的数据
}
}
// 2.在需要发送数据的线程创建Message
Message message = Message.obtain();__
// 3.调用接收线程的handler发送消息
handler.sendMessage(message);
主要类源码分析
1. Message
2. MessageQueue
MessageQueue 作为存放 Message 的容器。Handler机制中 最重要 的实现部分。
2.1 继承关系
// 无继承/无实现
public final class MessageQueue {
2.2 变量
// 如果消息队列可以退出,则该值为true。MainLooper为不可退出,其他Looper默认可退出
private final boolean mQuitAllowed;
private boolean mQuitting;// 正在退出的标识位
@SuppressWarnings("unused")
private long mPtr; // used by native code C++对象指针
Message mMessages; // 消息链表(有序,时间顺序)
// 是否唤醒的锁标识,true则表示native层正在等待唤醒
private boolean mBlocked;
// 同步消息屏障
private int mNextBarrierToken;
// IdelHandler 空闲消息
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
2.3 本地方法
private native static long nativeInit();// 本地创建循环
private native static void nativeDestroy(long ptr);// 本地销毁循环
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/// 本地拉去数据
private native static void nativeWake(long ptr);// 本地唤醒
private native static boolean nativeIsPolling(long ptr);// 本地判断是否在拉去
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
native 方法具体实现的是什么功能呢,其实他主要是在 C++ 层面实现了一个 消息阻塞 的功能。内部是使用了Linux的 多路复用/epoll 实现的。具体可以参考这篇博客。
对我来说可能需要以后再找时间攻克这个C++的源码
2.4 构造方法
该方法在 Looper 的 perpare() 中被调用。
// 可以看到,MessageQueue的构造方法是一个包权限
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
通过对构造方法的调用位置查看可知,MessageQueue 跟随 Looper 的创建而创建。在插入时,使用 自身对象锁,保证消息的处理顺序。
2.5 回收方法
// finalize是Java提供的回收方法,当对象被GC回收时调用,这里用来做一些native释放
@Override
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}
// Disposes of the underlying message queue.
// Must only be called on the looper thread or the finalizer.
// 这个注释说必须在回收的时候或者looper线程才能被调用
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
2.6 MessageQueue 的 hasMessage() 方法
这几个方法主要是根据传值的不同,甄别不同的消息进行判断
// 判断消息队列中是否含有指定what和object的消息
boolean hasMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}
// 判断消息队列中是否含有指定runnable和object的消息
boolean hasMessages(Handler h, Runnable r, Object object) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}
// 判断消息队列中是否含有指定Handler的消息
boolean hasMessages(Handler h) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h) {
return true;
}
p = p.next;
}
return false;
}
}
2.7 MessageQueue 的 next() 方法
该方法在 Looper 的 loop() 方法中被 循环调用。
// 依然是包权限
Message next() {
// 当loop已经结束的时候,直接返回null
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.
// 如果有同步消息屏障,找到链表中第一个异步的Message
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {// 如果消息没到,则取最小的时间休眠,然后进入IdleHandler逻辑
// 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 {
// 返回链表头的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;
}
// 如果需要关闭队列
if (mQuitting) {
dispose();
return null;
};
/// 下面的代码在 2.13 IdelHandler 机制 中分析
/// ...
}
}
2.8 MessageQueue 的 enqueueMessage() 方法
该方法在 Handler 中被调用,作用是向消息队列中添加 Message。
// 可以看到,也是包权限
boolean enqueueMessage(Message msg, long when) {
// 必须指定Handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 判断Message是否被使用
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) {// 或该消息需要执行的时间早于链表头所要执行的时间
// 将该消息至于链表头,同时通知native函数需要唤醒
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 如果是把数据加到链表的中间,通常我们不需要主动的通知唤醒,除非
// 1.在消息头存在同步消息屏障,即该消息的handler为空
// 2.这条消息需要异步执行
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;
}
// 因为 mQuitting是false, 所以我们可以认为mPtr != 0
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
该方法将 Message 根据时间添加到队列中,并根据逻辑来判断是否需要调用 唤醒 方法。
2.9 MessageQueue 的 removeMessage() 方法
2.9.1 移除特定消息
根据传递的参数不同来移除特定消息
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// 先确定链表头
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// 再过滤其他位置
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
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;
}
}
}
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (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 && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
2.9.2 移除所有消息
// 遍历回收所有的Message
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
//使loop()方法在处理完消息队列中所有要传递的剩余消息后立即终止。但是,在循环终止之前,将不会传递将来具有到期时间的挂起延迟消息。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {// 如果链表头的时间为未来时
removeAllMessagesLocked();// 正常移除所有消息
} else {
Message n;
for (;;) {
n = p.next;// 获取下一次需要传递的消息
if (n == null) {
return;
}
if (n.when > now) {// 下一次为未来时
break;
}
p = n;// 如果为过去时,则把它赋值给p
}
/// 循环结束则找到了所有过去时 的最后一个消息
/// 此时,p为倒数第二个过去时消息,n为最后一个过去时消息
p.next = null;
/// 移除所有未来时的消息
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
2.10 MessageQueue 的 quit() 方法
// 参数 safe 表示是否要移除当前队列中已到时间但没有来得及处理的消息
// true 表示不移除,false 表示全部移除
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
2.11 MessageQueue 的 isPolling() 方法
该方法可用于准确的判断 queue 是否处于轮询中(是否被阻塞)
public boolean isPolling() {
synchronized (this) {
return isPollingLocked();
}
}
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}
2.12 MessageQueue 的 dump() 方法
// 对当前MessageQueue状态的倾泻打印
void dump(Printer pw, String prefix, Handler h) {
synchronized (this) {
long now = SystemClock.uptimeMillis();
int n = 0;
for (Message msg = mMessages; msg != null; msg = msg.next) {
if (h == null || h == msg.target) {
pw.println(prefix + "Message " + n + ": " + msg.toString(now));
}
n++;
}
pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
+ ", quitting=" + mQuitting + ")");
}
}
2.13 MessageQueue 的 同步消息屏障方法
2.13.1 postSyncBarrier() 方法
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
// 向消息队列中插入一个handler为空的Message
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;// 将arg1 属性复制为token
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
2.13.2 removeSyncBarrier() 方法
// 根据arg1与token是否相等来移除同步消息屏障,重新nativeWake
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
2.14 MessageQueue 的 IdleHandler 机制
当 MessageQueue 中的消息都被响应后,MessageQueue 进入 Idle 状态,此时可执行 mIdleHandlers 中的消息
2.14.1 MessageQueue 的 IdleHandler 接口
public static interface IdleHandler {
// 返回false则从IdleHandlers中移除
boolean queueIdle();
}
2.14.2 MessageQueue 的 isIdle() 方法
// 消息列表为空或者消息列表要执行的时间没到
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}
2.14.3 MessageQueue 的 addIdleHandler()/removeIdleHandler() 方法
// 添加方法
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
// 移除方法
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
2.14.4 next() 方法中对 IdleHanlder 的使用
在同步代码块中,将List转换为Array
// 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)];// 最大数量控制在4以内
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
然后循环执行 Array 中的 IdleHandler,执行后从 List 中移除
// 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;
2.15 MessageQueue 的 FileDescriptor 机制
暂不知道这个是什么意思,是写日志或是?
2.16 总结
至此,MessageQueue 类的900多行代码,除了 FileDescriptor 部分就看完。这个类在整个 Handler 机制中属于最核心的处理部分。提供了对整个链表消息队列的增删查以及管理操作。最主要的:休眠唤醒采用了 native 代码调用 linux 部分实现。同时也提供了不少细节上的小用法,比如:同步消息屏障 ,IdleHandler 等。
其实接下来的 Looper 和 Handler 就比较简单了,就是基于 MessageQueue 对上层做出的封装。只要理解了 MessageQueue 的工作原理,到了 Handler 和 Looper 的源码部分,更要关注的是整个Handler机制是如何在整个Android系统中使用的。
网友评论