关于Handler通讯之前也看了好几遍,记忆慢慢模糊了,希望通过这次详细的整理能记忆的更久。本篇涉及的类比较多,为了更好的记忆,我采用了先整体在局部的叙事方式。先整体把流程梳理,再详细说明流程中涉及到的某些类。
首先通过以往的章节源码学习,我们对一下流程应该都熟悉了
- init 进程,zygote进程,systemserver进程的启动
- PMS启动后解析manifest.xml文件数据到application
- AMS启动launcher,systemui
- AMS 创建应用进程
- LoadedApk 资源文件的加载(换肤)
- ClassLoader 类加载器(热修复)
今天就来学习,AMS创建应用进程之后,发生了什么。从主线程引入Handler等的流程。把Handler通讯分两部分
- 线程中Looper的创建,开启无线循环从队列中取出消息
- handler发送消息到 MessageQueue队列排序
1. 线程中Looper的创建和开启无线循环获取msg
- 首先我们从ActivityThread main() 进入Looper的创建流程
public static void main(String[] args) {
// 为 当前 app 创建私有用户存储文件夹
Environment.initForCurrentUser();
// 为当前线程创建looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 开启无线循环,获取消息队列中的消息
Looper.loop();
}
通过上述代码Looper.prepareMainLooper()调用到了Looper中。
public static void prepareMainLooper() {
// 创建looper
prepare(false);
synchronized (Looper.class) {
// 判断是否已经创建过
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 赋值到全局变量
sMainLooper = myLooper();
}
}
通过prepareMainLooper进入 prepare()方法创建looper对象
private static void prepare(boolean quitAllowed) {
// 判断当前线程是否已经创建过了 looper 对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 未创建looper对象
sThreadLocal.set(new Looper(quitAllowed));
}
根据代码很容易发现looper对象创建过程中,代码转入到了 ThreadLocal 对象,那ThreadLocal又是什么呢?
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal<Looper> 是Looper类中的 static 的全局变量,说明sThreadLocal 是属于类的,并且被保存在老年代内存中。 所以不管有多少个Looper对象对应的ThreadLocal<Looper>对象只有一个,那怎么可能维护不同线程不同的looper对象的呢,其实ThreadLocal<Looper>中维护了一个ThreadLocalMap来保存Looper对象的。先来看看ThreadLocal<Looper>的get() set() 方法。
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 根据线程获取 map 对象
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;
}
}
// 为null 就创建一个新的
return setInitialValue();
}
void createMap(Thread t, T firstValue) {
// ThreadLOcalMap 是一个线程的全局变量
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
public void set(T value) {
Thread t = Thread.currentThread();
// 根据线程取map
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
// 没有创建
createMap(t, value);
}
对于 ThreadLocalMap 原理根据这篇文章学习 https://blog.csdn.net/weixin_41344042/article/details/83024039
通过以上流程发现 我们创建的looper对象是被保存到Thread中的ThreadLocalMap t 的全局变量中。
- Looper的无线循环
// 开启无线循环,获取消息队列中的消息
Looper.loop();
根据上述代码知道,在looperprepare 之后就调用了 loop() 方法开启循环,具体怎么循环的,接下来看代码
public static void loop() {
// 获取当前线程的looper对象
final Looper me = myLooper();
// 获取 Message 队列
final MessageQueue queue = me.mQueue;
// 死循环 获取message
for (;;) {
// Message 是个单向列表
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
// 通过转发给 handler 持行当前消息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
}
}
从loop方法中看到首先是获取当前loop 的MessageQueue队列,从队列中取出地一个message,然后发出去。这个过程涉及到了MessageQueue的 next()和handler 的 dispatchMessage()方法。
Message next() {
// 指针
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
// 下次执行 nativePollOnce(ptr, nextPollTimeoutMillis); 的时间
int nextPollTimeoutMillis = 0;
for (;;) {
// 持行延迟消息
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 获取当前时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 获取第一个 handler 不为null的消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 当前时间小于 msg的发送时间,就是消息还没到持行的时间点,
if (now < msg.when) {
// 下一次持行nativePollOnce(ptr, nextPollTimeoutMillis);的时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 获得一个消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
// 把发送出去的消息,从队列中移除
msg.next = null;
// 返回 msg 给handler
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
nextPollTimeoutMillis = 0;
}
}
Message 消息是一个单向列表,这个列表由 MessageQueue 类来管理,MessageQueue 中next()方法用来获取message这个消息,发给handler 处理。
以上就是线程中Looper的创建和开启无线循环过程。
2. handler发送消息到 MessageQueue队列排序
在 1 中已经引出了 looper 从队列中取出消息的过程,接下来看下消息加入到队列中。
通过对以上looper.loop() 开启了无线循环获取message,这时message队列中还没有msg,我们调用handler方法向队列中发送msg。
调用 handler 的发送消息方法都会走到这里
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
// 当前时间 + 延迟时间
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
然后走到 MessageQueue 中的 enqueueMessage() 方法。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
// 获取当前队列中的 msg的时间
msg.when = when;
Message p = mMessages;
boolean needWake;
// 把消息排序,把传入的消息 放到head头部
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 (;;) {
// 把 head 头赋值给prev
prev = p;
// 取出 第二个消息
p = p.next;
// 根据时间 排序,来定义 消息持行的顺序
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 把msg插入到head头的后面第一个
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
这里就是消息排序,把消息放入到MessageQueue队列中,然后等待looper.loop()去获取消息,然后分发给handler去处理。