「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
这里主要分析Handler 源码
一、Handler 定义
更新 UI 界面的机制,也就是消息处理,可以发送消息,处理消息
二、 原理
Handler:封装消息的发送(主要包括消息发送给谁)
Handler 内部是通过 post 方法将 Runnable 投递到 Handler 的 Looper 处理,或者通过 send
发送信息到 Looper 处理,post 最终也是调用 send 方法调用。
Looper:消息封装的载体。内部包含一个 MessageQueue,所有的 Handler 发送的消息
都走向这个消息队列;Looper.Looper 方法,就是一个死循环,不断地从 MessageQueue 取消
息,如果有消息就处理消息,没有消息就阻塞
它的特点是它跟它的线程是绑定的,处理消息也是在 Looper 所在的线程去处理,所以当我
们在主线程创建 Handler 时,它就会跟主线程唯一的 Looper 绑定,从而我们使用 Handler 在
子线程发消息时,最终也是在主线程处理,达到了异步的效果。
Handler 内部与 Looper 关联,handler->Looper->MessageQueue,handler 发送消息就是
向 MessageQueue 队列发送消息
MessageQueue:主要是两个操作,插入和读取,读取伴随着删除。enqueueMessage 和
next 两个操作,MQ 数据结构是通过链表完成,通过 enqueueMessage 完成入队的操作,即
链表的插入,而 next 里面是一个死循环,当有消息时会通过调用 next 方法从单链表里移出,
没有时则阻塞
总结:handler 负责发送消息,Looper 负责接收 handler 发送的消息,并把消息回传给
handler 自己,MessageQueue 存储消息
三、为什么在子线程实例化 handler 就不行呢?
handler在子线程中实例化Handler之前要注意先调用 Looper.prepare() 方法。不然会报下面的错误
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: "+klass.getCanonicalName());
}
}
// 获取我的轮询器
mLooper = Looper.myLooper();
if (mLooper == null) {
// 在实例化 Handler 时, mLooper 为空的时候就会抛出这个异常
throw new RuntimeException("Can't create handler inside thread that has not called
Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
问题找到了,Looper 为空,接下来载看看 Looper 里的
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}