android Handler消息机制实现原理
网上关于Handler实现机制的介绍很多,本文主要写自己关于Handler的一些理解
1.一些常见疑问解答
Q1:简述Handler消息机制的实现原理
A1:Handler对象在创建的时候,会有一个Looper初始化,初始化的同时会创建一个MessageQueue对象,并启动消息循环,当调用sendMessage方法的时候,会调用到MessageQueue的enqueueMessage方法将消息插入消息队列,在此方法里面,会调用nativeWake来唤醒Looper,取出队头消息,然后通过target.dispatchMessage方法来分发消息,最终在Handler.handleMessage方法里面处理消息
Q2:Handler发送消息需要哪些条件
A2:Handler必须有一个关联的Looper对象来实现消息循环,有2种获取Looper方法,一是使用当前Activity所在主线程的Looper;二是自己创建一个Looper对象,继承HandlerThread,此类内部有实现一个Looper对象
Q3:Looper对象怎么创建,主线程的Looper对象是什么时候创建的
A3:Looper提供了prepare和prepareMainLooper方法来创建Looper对象;主线程的Looper对象是在ActivityThread的main方法里面创建的
Looper.prepareMainLooper();
Looper.loop();
Q4:Looper消息是循环的,在等待的过程中,为什么没有阻塞主线程
A4:Looper消息循环其实是调用MessageQueue.next方法来实现的,在next方法里面,使用的一个native方法nativePollOnce来实现,利用linux epoll机制来实现
Q5:怎么创建一个Message对象
A5:Message没有提供构造方法,一般建议使用obtain方法来复用Message,用完后使用recycleUnchecked来回收,只是把对象里面的属性全部重置,对象未删除;内部有消息池,最大支持50个,超过50个则不再创建新的Message对象
2.关键类属性及方法接受
MessageQueue.java是串联Java层和Native层的关键,内部定义了几个native方法,用来和native层进行交互
2.1 Java层主要相关的类:
代码路径:
frameworks/base/core/java/android/os/Handler.java
frameworks/base/core/java/android/os/MessageQueue.java
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/os/Message.java
-
Handler 用来发送和执行Message和Runnable
- Looper mLooper 关联的Looper实例
- MessageQueue mQueue 关联的mQueue实例
- Callback mCallback 回调CallBack
- final boolean mAsynchronous 是否异步
-
MessageQueue 消息队列,消息不能直接添加, 需要通过Handler
- long mPtr 给Native用的,代表Native层的MessageQueue
- native static long nativeInit() 构造方法中给mPtr初始化
- native void nativePollOnce 阻塞的获取一条消息
- next() 获取队列中的下一条消息,在Looper对象中被调用
-
Looper 给一个线程执行消息循环,线程默认是没有相关联的Looper的
- Looper sMainLooper 主线程的Looper
- MessageQueue mQueue 关联的MessageQueue
- Thread mThread Looper所处的线程
- ThreadLocal sThreadLocal 用来保存和当前进程关联的Looper对象
- prepare()和loop() 创建Looper对象的个步骤
- public static void loop() 启动消息循环,在一个死循环中调用queue.next()方法来获取下一条消息
-
Message 代表一个消息
- public int what 消息值
- public Object obj 消息所带的对象
- Handler target 消息被处理的Handler
- Message sPool 消息池,最大支持50个,建议通过obtain()方法来复用,recycleUnchecked来回收,只是把对象里面的属性全部重置,对象未删除
2.2 Native层主要相关的类:
代码路径
framework/base/core/jni/android_os_MessageQueue.cpp
system/core/libutils/Looper.cpp
system/core/include/utils/Looper.h
system/core/libutils/RefBase.cpp
framework/base/native/android/looper.cpp
framework/native/include/android/looper.h
3.实现原理
3.1.Looper对象创建
Handler的创建很简单,重点看一下Looper对象的创建。对外提供2种创建的接口
- prepare 一般自定义的Looper使用这个方法,可以退出循环
- prepareMainLooper 给应用的主线程创建Looper
// 私有构造方法,初始化mQueue和设置关联的mThread,只能通prepare方法创建对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static void prepare() {
prepare(true); // 默认是可以退出
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 每个线程只能创建一个Looper
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false); // mainlooper不能通出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
对象实现比较简单,利用sThreadLocal来保存Looper对象,供线程内部使用。
对象创建完后,调用loop()方法进入循环,主要有4个动作
- 获取MessageQueue对象
- 获取下一条要处理的消息
- 将Message发送给对应的Handler来处理
- 回收消息
public static void loop() {
final Looper me = myLooper();
// 1.获取MessageQueue对象
final MessageQueue queue = me.mQueue;
for (;;) {
// 2.获取下一条要处理的消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
// 3.将Message发送给对应的Handler来处理
msg.target.dispatchMessage(msg);
} catch (Exception exception) {
} finally {
}
// 4.回收消息
msg.recycleUnchecked();
}
}
初始化的时候,MessageQueue是空的,会阻塞在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;
}
for (;;) {
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.
// 找到next Message则返回
return msg;
}
} else {
}
}
}
}
nativePollOnce最终会调用到Looper::pollOnce()方法,空闲时停留在epoll_wait()方法,用于等待事件发生或者超时
3.2 MessageQueue对象创建
看MessageQueue的构造方法
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
nativeInit方法是在android_os_MessageQueue.cpp文件里面实现的
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
//初始化native消息队列
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
在NativeMessageQueue方法里面,会创建一个Looper对象,此处Native层的Looper与Java层的Looper没有任何的关系,只是在Native层重实现了一套类似功能的逻辑。
NativeMessageQueue::NativeMessageQueue()
: mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false); //创建native层的Looper
Looper::setForThread(mLooper);
}
}
在Looper的rebuildEpollLocked方法里面,会利用epoll机制来实现消息处理机制
void Looper::rebuildEpollLocked() {
// Close old epoll instance if we have one.
if (mEpollFd >= 0) {
mEpollFd.reset();
}
// Allocate the new epoll instance and register the wake pipe.
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
strerror(errno));
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd.get();
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
}
}
epoll操作过程有3个方法,分别是epoll_create(), epoll_ctl(),epoll_wait()。
3.3 Handle.sendMessage
Handle.sendMessage通过层层调用,最终会调用到enqueueMessage方法
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);
}
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
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 3.1 步的阻塞
nativeWake(mPtr);
}
}
return true;
}
消息保存在链表里面,成功插入后,调用nativeWake方法来唤醒在3.1 步的阻塞queue.next()
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
void NativeMessageQueue::wake() {
mLooper->wake();
}
void Looper::wake() {
uint64_t inc = 1;
// // 向管道mWakeEventFd写入字符1
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
mWakeEventFd.get(), nWrite, strerror(errno));
}
}
}
其中TEMP_FAILURE_RETRY 是一个宏定义,当执行write失败后,会不断重复执行,直到执行成功为止。nativePollOnce从epoll_wait方法中退出,继续执行后面的,next方法返回一个Message对象
在3.1节Looper.loop()方法中获取到Message对象后,分发给对应的Handler
3.4 Handle.handleMessage
先看dispatchMessage方法,里面定义了响应规则
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- 如果有Message.callback非空,则会执行Runnable callback
- 如果mCallback非空,则调用mCallback.handleMessage
- 最后才调用handleMessage,走到我们复写的handleMessage方法
3.5 Message.recycleUncheck
此方法里面,只是重置了Message对象的相关属性,没有删除对象,保存消息池里面
消息池最大容量是50,超过则不再记录,obtain方法会消耗里面的资源
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++;
}
}
}