Handler 是Android最常用的消息机制,很多地方都在使用,如四大组件的创建和使用,view的渲染机制等等,我们平时开发过程中也会经常用到,使用Handler发送一个消息后,他会按照消息的时间,按照顺序来进行分发,分析Handler可以从两个方向解析,1、Java方面 2、native方面。
首先先从Java方面开始解析。
Java层面分析
常用类分析
ThreadLocal
用于保存Looper对象,内部是用Thread线程对象来保存Looper的,也就是说,一个线程只能有一个Looper,一个Looper有一个MessageQueue,但是可以有多个Handler 在Looper中是这样定义ThreadLocal的
Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal内部有几个核心方法如下
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
因为Looper的创建是在当前线程中,所以在子线程中,是没有默认创建Looper的,所以在子线程中调用Looper.myLooper()返回的是null
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper
Looper负责将MessageQueue中的消息通过loop()方法来取出来, 构造函数创建了MessageQueue对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
内部还有几个常用的方法
正常创建Looper quitAllowed代表是否可以安全退出 创建Looper后是保存到ThreadLocal中,这个后续分析。
正常创建Looper quitAllowed代表是否可以安全退出
创建Looper后是保存到ThreadLocal中,这个后续分析
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));
}
在ActivityThread的main()方法中调用的这个方法,即在应用启动后,就会创建一个主线程的Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
loop()方法,是核心方法,通过死循环的方式来不断的从MessageQueue队列中获取message消息。最后走到了MessageQueue的next()方法中。
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;
for (;;) {
Message msg = queue.next();
}
}
Message
Message是消息的数据模型,是以链表的形式存在,内部有几个关键的参数,如下
public final class Message implements Parcelable {
public int what; 消息的标识
public Object obj; 消息的数据
Handler target; 表示是哪一个Handler所属的消息
Runnable callback; 消息内部的回调方法
Message next; 以链表的形式存储,下一个
int flags; 用来标识是否是异步消息,不受同步屏障的的影响消息
}
Message内部的核心方法 obtain()方法表示从内部sPoolSync消息池中获取消息。用来复用,避免重复创建
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();
}
recycle()方法是回收Message的方法,如果消息池中的数量小于最大消息数量50的时候,就可以往消息池中继续添加消息。
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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
setAsynchronous方法表示是否是一个异步消息,后面存储和获取是会结合同步屏障来处理。
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
Handler
发送消息的源头,我们来看一下通常的使用方法: 发送一个空消息,和post一个延迟的消息,runnable中执行具体的方法。
val handler = Handler(Looper.getMainLooper())
handler.sendEmptyMessage(1)
Handler(Looper.getMainLooper()).post({
})
Handler(Looper.getMainLooper(),object : Handler.Callback{
override fun handleMessage(msg: Message): Boolean {
return false
}
})
我们开始跟踪一下内部的实现
1.向MessageQueue中发送消息
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
分别的作用是,从线程池中获取一个空的Message,然后把当前的时间和delay时间算好后,作为when,作为后面插入到MessageQueue有序队列中的依据。然后target标记当前Handler。如果是异步消息则设置上,不过正常的消息都是同步消息。
最后交给了MessageQueue来进行添加Message。
2.Handler接受消息
进行消息的方法,其中有三种情况
- 消息本身的callback,即上面的post
- callBack 在构造函数中传入callback
- 继承Handler 重写handleMessage方法
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
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);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
MessageQueue
向MessageQueue中存消息和取消息都是在MessageQueue方法中,下面继续分析一下。
存消息时,1.如果没有头节点,或者when为0 或者当前消息的时间小于Message队列中的头节点的消息的时间,则将当前这个message插入到头节点,然后设置needWake=true,来通知looper进行取数据。2.如果当前消息并不小于头节点的消息。 3.判断如果头节点是同步屏障,且当前消息是异步消息,则需要唤醒looper。4.根据时间来插入消息。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//1.如果没有头节点,或者when为0 或者当前消息的时间小于Message队列中的头节点的消息的时间,则将当前这个message插入到头节点,然后设置needWake=true,来通知looper进行取数据。
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 {
//2.如果当前消息并不小于头节点的消息
//3.判断如果头节点是同步屏障,且当前消息是异步消息,则需要唤醒looper
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;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
读取消息
- 首先使用epoll机制来阻塞线程
- 如果头节点消息是同步屏障,则获取同步屏障后的异步消息
- 如果消息的时间大于当前时间,则记录需要唤醒的延迟时间
- 链表常规操作,将当前msg取出
- IdleHandler 的消息处理
Message next() {
...
for (;;) {
//1.首先使用epoll机制来阻塞线程
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
Message prevMsg = null;
Message msg = mMessages;
//2.如果头节点消息是同步屏障,则获取同步屏障后的异步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//3.如果消息的时间大于当前时间,则记录需要唤醒的延迟时间
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//4.链表常规操作,将当前msg取出
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
//5.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);
}
}
}
nextPollTimeoutMillis = 0;
}
}
同步屏障
Handler 同步屏障和异步消息
在MessageQueue中的postSyncBarrier()方法进行发布一个同步屏障消息。主要是在消息列表的头节点前插入一个Message,但是没有使用enqueueMessage方法来进行插入,而是在头节点前直接插入,此时这个消息的target为空。
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.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;
}
}
接下来看一下ViewRootImpl中的scheduleTraversals()方法中是如何发布一个同步屏障的,在Vsync信号接收到后,开始渲染上一桢的view时,会回调到scheduleTraversals()方法。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
- 首先调用postSyncBarrier()来发一个同步屏障。
- 然后调用Choreographer的postCallback()方法来发送一个异步消息,setAsynchronous(true);来设置异步消息
- 在接受到消息的回调后,需要及时的移除同步屏障,否则就不会再接受其他的同步消息了。移除后,再判断是否要唤醒looper
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
public void removeSyncBarrier(int token) {
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 (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
Native层面
native层面主要分析 nativeinit nativePollOnce 和 nativeWake 唤醒和阻塞两个方法,其中native方法的调用是在MessageQueue中。
MessageQueue.java
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
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);
1. nativeinit()
nativeinit()方法是在MessageQueue的构造方法中调用。
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
那继续跟踪native层的代码
frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
创建了NativeMessageQueue native层的MessageQueue消息队列 并将NativeMessageQueue对应的指针mPtr返回给Java层的MessageQueue中,以便后面的nativePollOnce使用 继续看一下NativeMessageQueue frameworks/base/core/jni/android_os_MessageQueue.cpp
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
如果当前线程下有Looper就直接返回,没有的话就创建一个,也是一个线程有一个Looper。 创建了一个native层的Looper,跟Java层的没有什么关系,而且读取操作都放在了Looper这个类当中,跟Java的不一样,Java的都放在了MessageQueue中。
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
rebuildEpollLocked();
}
Looper中主要做了两件事情:
- 构造唤醒事件的fd(文件操作符)mWakeEventFd
- 重建epoll机制
总结一下nativeinit方法
- 创建NativeMessageQueue,进而创建Looper。
- 构造唤醒事件的fd 文件操作符mWakeFd和重建epoll机制,即通过管道和epoll机制创建一套消息机制
- 将NativeMessageQueue对象转换成Long类型存储到Java层的MessageQueue的mPtr中
2.nativePollOnce()
Java层Looper.loop() 调用MessageQueue.next()方法时,会调用nativePollOnce()
//MessageQueue.java
Message next() {
for(;;){
nativePollOnce(ptr, nextPollTimeoutMillis);
}
}
当没有消息时,nativePollOnce会进入阻塞
nativePollOnce方法总结
- 将ptr转化成NativieMessageQueue,并调用其pollOnce方法,最后会调用到Looper的pollInner方法
- Looper的pollInner方法是一个阻塞方法,内部有epoll_wait方法,如果没有消息时会阻塞,并释放cpu资源,epoll_wait方法会监听创建的epoll文件操作符所监听的事件,如果发生变化,会从管道中读取放入到事件集合中,如果没有事件,epoll_wait方法会让当前线程进入休眠。
- 读取到消息后,会通过native层的Handler发送一个Message消息。处理完后会返回到Java层,
3.nativeWake()
Java层的MessageQueue.enqueueMessage方法调用时,会判断是否需要调用nativeWake(),当有新的消息存入时,会调用nativeWake来通知Looper进行读操作。
//frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
//frameworks/base/core/jni/android_os_MessageQueue.cpp
void NativeMessageQueue::wake() {
mLooper->wake();
}
//system/core/libutils/Looper.cpp
void Looper::wake() {
uint64_t inc = 1;
//使用write函数通过mWakeEventFd往管道写入字符inc
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
//...
}
最后调用到native层的Looper.wake方法。通过write函数,通过mWakeEventFd往管道中写入字符inc,然后我们在nativeInit方法中创建的mWakeEventFd文件操作符,会监听是否有可读事件,如果有的话,就会让epoll_wait方法从管道中读取事件并返回。
参考链接: www.jianshu.com/p/ac3cd5a19… www.jianshu.com/p/57a426b8f…