Android Framework提供的一个基础组件,用于线程间通讯。主要是子线程UI更细消息传递给主线程,从而主线程更新UI。java
Android 主线程的UI,只能主线程更新。 若是多个线程都能更新,势必要「加锁」,还不如采用「单线程消息队列机制」android
主线程内部维护一个循环。没有消息时候,这个循环是阻塞的。新来消息(或者阻塞timeout)时会唤醒,接着处理新到来消息。git
整个handler能够粗略的分为三个过程数组
咱们使用Handler第一感官是发消息,因此从发消息切入。缓存
咱们先来看发送消息,这是咱们最简单的一种发送消息的方式。markdown
//构建一个处理message的handler
val handler = object : Handler() {
override fun dispatchMessage(msg: Message) {
Log.d("alvin", "msg.what:${msg.what}")
}
}
var msg = Message().also { it.what = 1 }
handler.sendMessageDelayed(msg,1000L)
复制代码
稍稍追踪下代码咱们发现,有不少sendMessage方式,都统一到一个方法中即app
//Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;//这个分发用的,省略了一下其余代码
return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码
接着调用到MessageQueue.enqueueMessage(Message msg, long when),代码在下面, 解释下,咱们有一个单链表message,message有next指向下一个message,以及此message触发时间when。单链表是有顺序的,when越小,就越靠前。 根据when,新message插入合适位置,若是刚好插在队首,则须要唤醒nativeWake。因此归结下来两件事情:入队和唤醒。ide
//MessageQueue.java 忽略一些代码了,只关心,咱们此次走到的逻辑
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.when = when;
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 {
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) break;
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) nativeWake(mPtr);
}
return true;
}
复制代码
咱们主要到构建一个Handler会调用到MessageQueue.javaoop
val handler = object : Handler()
-->mLooper = Looper.myLooper();
-->sThreadLocal.get()
ActivityTread.main()
-->Looper.prepareMainLooper()//构建当前线程的Looper
-->Looper.prepare()
-->new Looper(quitAllowed)
-->mQueue = new MessageQueue(quitAllowed);
-->mPtr = nativeInit()
-->Looper.loop();//启动轮询
复制代码
那主线程的Looper哪里来的,早在应用主线程被启动时,咱们便post
//ActivityTread.java
class ActivityTread{
public static void main(String[] args) {
Looper.prepareMainLooper();
}
}
//Looper.java ,省略了部分代码
class Looper{
/** *能够看到sThreadLocal中的Looper只能被设置一次 */
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));
}
/** * 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);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
}
复制代码
Looper.loop() 省略部分代码。就堵塞在这了nativePollOnce(ptr, nextPollTimeoutMillis)。 此处没有用java中的wait/notify堵塞,而是经过Linux的epoll机制
来堵塞,缘由是须要处理 native侧
的事件。 没有消息时堵塞并进入休眠释放CPU资源,有消息时再唤醒线程。 epoll参考:epoll的本质
class Looper{
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
// 1.阻塞,直到next有返回值。
Message msg = queue.next();
//2.后面提到的消息分发处理
msg.target.dispatchMessage(msg);
}
}
}
class MessageQueue {
Message next() {
/**等于0时,不堵塞,当即返回; *大于0时,最长堵塞等待时间,期间有新消息进来,可能会了当即返回(当即执行); *等于-1时,无消息时,会一直堵塞; */
int nextPollTimeoutMillis = 0;
for (;;) {
//阻塞在此,超时或者被唤醒时,执行接下来的代码
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
//咱们发现拿到的第一个消息,执行时间还没到,那咱们计算下超时时间,用于下一次的nativePollOnce
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.提取这个消息,并如下一个消息从新做为消息头
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}
}
}
复制代码
在Looper.loop()中执行了 msg.target.dispatchMessage(msg); msg.target就是咱们的Handler对象。
早在Handler.enqueueMessage(msg,...)时,咱们执行了
msg.target = this;
class Handler{
public void dispatchMessage(@NonNull Message msg) {
//msg.callback跟踪下代码。哦,原来是post(Runnable),时候构建一个带callback的message
if (msg.callback != null) {
handleCallback(msg);//-->message.callback.run();
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//咱们并无给handler设置mCallback,因此执行handleMessage
handleMessage(msg);
}
}
//post(Runnable),时候构建一个带callback的message
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
}
复制代码
虽然主流程没有了问题,但咱们省略了不少代码,能够做为问题来探索这些省略的代码
消息轮询机制是经过MessageQueue.nativePollOnce()挂起和MessageQueue.nativeWake唤醒。 MessageQueue经过mPtr变量保存NativeMessageQueue对象,从而使得MessageQueue成为Java层和Native层的枢纽,既能处理上层消息,也能处理native层消息;下面列举Java层与Native层的对应图。 要注意的是Java层和C++层分别实现了一套Handler机制代码。
Java层:new Looper()-->new MessageQueue()-->mPtr = MessageQueue.nativeInit() -->native层:android_os_MessageQueue_nativeInit()-->new NativeMessageQueue()-->new Looper(false) 最终走到了Looper.cpp的构造方法
Looper::Looper(bool allowNonCallbacks)
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;//监听mWakeEventFd有写入数据。
eventItem.data.fd = mWakeEventFd.get();
//建立 eventpoll 对象,返回一个 epfd,即 eventpoll 句柄。
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
}
复制代码
要说 epoll_ctl()干吗用的,我也不太会了, 能够参考。
从Java层分析咱们获得Looper.loop()-->MessageQueue.nativePollOnce(mPtr,timeout) 进入native层:android_os_MessageQueue_nativePollOnce()-->NativeMessageQueue::pollOnce() -->Looper::pollOnce()-->Looper::pollInner() 一顿操做进入到了Looper::pollInner()
int Looper::pollInner(int timeoutMillis) {
//1.timeoutMillis处理,省略...
//2.开启等待,监听mWakeEventFd写入事件
//events 表示回传处理事件的数组;
//maxevents 表示每次能处理的最大事件数;
//timeout:等待 IO 的超时时间,-1 表示一直阻塞直到来 IO 被唤醒,大于 0 表示阻塞指定的时间后被唤醒
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//3.后面等唤醒后执行,先执行native层添加的message,逻辑与java层处理消息相似。
//4.走回java层,MessageQueue.nativePollOnce(),执行java层的消息提取。
}
复制代码
根据前面Java层分析,进入到MessageQueue.nativeWake() 进入native层:android_os_MessageQueue_nativeWake()-->NativeMessageQueue::wake()-->Looper::wake() 一顿操做进入Looper::wake()
void Looper::wake() {
uint64_t inc = 1;
//往mWakeEventFd里面写了1,随后进入到Looper::pollInner(),唤起”epoll_wait“,继续执行。
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}
复制代码
int Looper::pollInner(int timeoutMillis) {
//1.timeoutMillis处理,省略...
//2.开启等待,监听mWakeEventFd写入事件,省略...
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//Looper::wake()后执行到这。
//3.后面等唤醒后执行,先执行native层添加的message,逻辑与java层处理消息相似
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
if (messageEnvelope.uptime <= now) {
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
handler->handleMessage(message);
} else {
// The last message left at the head of the queue determines the next wakeup time.
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
//4.走回java层,MessageQueue.nativePollOnce(),执行java层的消息提取。
}
复制代码
与Java层相似,但同时咱们省略了不少代码,带着问题继续看代码