1、简介
Android Handler消息机制由Handler、Looper、Message、MessageQueue组成。
- Handler - 负责发送并处理Message
- Message - 消息的承载体
- MessageQueue 消息队列 - 存储Message对象
- Looper 轮询器 - 不断从MessageQueue中去轮询是否有Message对象
2、Handler消息机制的作用
两个主要作用:
- 调度Message或在某个时刻执行Runnable
- 线程间的通信
3、Looper与线程相关联
下面以主线程的Looper为例
ActivityThread
public static void main(String[] args) {
//省略代码
//初始化主线程的Looper
Looper.prepareMainLooper();
//省略代码
if (sMainThreadHandler == null) {//创建主线程的Handler
sMainThreadHandler = thread.getHandler();
}
//开启Looper循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//创建主线程的Looper
sMainLooper = myLooper();
}
}
public static @Nullable Looper myLooper() {
//通过ThreadLocal获取,ThreadLocal是线程的成员变量
return sThreadLocal.get();
}
ThreadLocal
public T get() {
//获取当前的线程
Thread t = Thread.currentThread();
//ThreadLocalMap也是Thread的成员变量
//ThreadLocalMap是一个Map结构,以ThreadLocal为Key值。在这里Value的是Looper对象
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通过调用myLooper()方法初始化Looper对象,Looper对象持有一个ThreadLocal对象,这个ThreadLocal存储了当前的Looper对象,然后把Looper对象持有的ThreadLocal对象存储到Thread的ThreadLocalMap中。
4、Handler与线程相关联
public Handler(@Nullable Callback callback, boolean async) {
//省略代码
//初始化Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
总结:当Handler创建的时候,Handler持有Looper对象也会通过Looper.myLooper()方法进行初始化,从而使得Handler、Looper都关联到同一个线程。从上面我们也可以得知,为什么当在子线程中创建其所属的Handler时必须调用Looper.prepare()。在主线程不需要调用是因为在主线程启动的时候,系统以及为我们调用了相应的方法。
5、Looper.loop()通过死循环开启轮询为什么不会ANR
Android是事件驱动的Linux操作系统Looper.loop()不断的接收处理事件,Looper.loop() 一旦退出,应用程序的
也就结束了。发生ANR使用事件没有得到处理或者事件正在处理,但是没有及时完成。另外当MessageQueue中没有消息时,会调用nativePollOnce()方法,主线程会释放CPU资源进入休眠状态,直到下条消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作,采用的是epoll机制。
Message next() {
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();
}
//当没有Message时,进入该方法
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.
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;
}
}
//省略代码
}
}
网友评论