ㅤㅤㅤ
基本每次 Android 面试都会问 Handler 的原理,基本每次都要回去背一次 Handler 原理,就没有一种把 Handler 原理讲通透不会忘记的文章吗?
ㅤㅤ ㅤ ㅤ ㅤ
1.首先要记住谁才是核心:ThreadLocal
Handler 的主要作用是线程间通信。在 Handler 架构流程中有一个类叫 ThreadLocal,先不用记住它的名字,主要是它里面有一个 Map,这个 Map 的 Key 是某个线程,而 Value 是 Looper。这个 Looper 需要狠狠记住,因为它是处理消息的核心。
"线程 --> Looper",按照我结合现实世界的理解的话,一条流水线需要一个工人处理一个个产品,这里的流水线是一条线程,处理这个流水线的工人是 Looper,它是唯一的,因为在一条流水线上一个人处理是很合理,不会出现手忙脚乱的情况。(高中进厂流水线暑假工的经历,看来真的有用😂)
mindmap
ThreadLocal
Map
Looper
线程
有了流水线,招到了工人,就开始干活了。
ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
2. Looper 中的 MessageQueue
这个很好理解,工人负责的产品线。在创建 Handler 中的 Looper 的时候,它就被创建了。它是 Looper 的成员变量,因为处理消息(也就是处理产品线产品)的核心是人(Looper)。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); // 核心代码
mThread = Thread.currentThread();
}
ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
3. 为什么子线程不能直接使用 Handler
了解上面的 ThreadLocal 后,这个问题迎刃而解。### 2. 为什么子线程不能直接使用 Handler
了解上面的 ThreadLocal 后,这个问题迎刃而解。在源码中,Android 的 ActivityThread 在main方法中已经创建了主线程对应的 Looper,所以我们在主线程使用 Handler 不用创建 Looper。
/**
ActivityThread 创建 Looper 流程代码
*/
public static void main(String[] args) {
...
Looper.prepareMainLooper();// 核心代码
...
}
public static void prepareMainLooper() {
prepare(false); // 核心代码
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 当前主线程的 Looper 为空需要创建一个 Looper
sThreadLocal.set(new Looper(quitAllowed));
}
而在子线程中,因为 ThreadLocal 以子线程为 Key 找不到对应的 Value,也就是 Looper,自然就报错,没有工人你干什么活?
public Handler(Callback callback, boolean async) {
...
// 核心代码,在当前子线程中拿不到 Looper,报错,也就是无法在子线程创建 Handler
mLooper = Looper.myLooper();
if (mLooper == null) { Handler
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
...
}
那怎么办?很简单,学主线程中调用 Looper.prepare() 方法就行了。
ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
4. 不同线程间通信
在电子厂加工一个电子设备,不同流水线之间需要沟通,比如在流水线 A 对设备进行电阻的安装,安装好后把设备传给流水线B对设备进行显示屏的安装。这就是线程间通信的现实例子。流水线A类别网络请求的线程,流水线B类别UI线程。
子线程中拿到主线程的 Handler,通过 sendMessage() 把 Message 发送到自己 Looper 中的 MessageQueue 中,然后进行死循环取出 Message 最终调用 handleMessage() 方法对消息进行处理。这样就完成了线程间的通信。所以 Handler 只是作为消息发送的最表面的那一层,相当于经理把流水线A准备好的消息告诉流水线B的人(Looper)。
ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ
ㅤㅤㅤ ㅤㅤㅤ