前言
- 在Android中经常使用多线程开发,Handler则是基础,那么本文主要以流程+源码的形式来记录这种机制
Why?
为什么需要Handler?
我们需要切换线程处理UI,是因为ViewRootImpl#checkThread()中会判断创建View的线程是否与修改View的线程为同一个
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
How?
Android中是如何设计的?
使用不同的类协作完成
名称 | 作用 |
---|---|
Message | 存储信息数据 |
MessageQueue | 存储Message |
Looper | 循环/处理消息 |
Handler | 发送和接受消息 |
流程图
结合源码
提前的预备:线程中需要提前创建Looper和MessageQueue
- 创建Looper的两种方式
Looper.prepare();
Looper.prepareMainLooper();
Looper的构造方法是私有的只允许这两种方式创建
//普通的创建 Looper.prepare();
private static void prepare(boolean quitAllowed) {
//ThreadLocal封装了一个ThreadLocalMap(key:ThreadLocal<?>,value:Obj)保存线程和Looper的信息
//如果获取到了就说明这个线程有对应的Looper对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将Looper和当前线程信息保存
sThreadLocal.set(new Looper(quitAllowed));
}
//主线程创建 Looper.prepareMainLooper();
//在ActivityThread的main方法中
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
- 创建MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
创建Looper的时候就顺带创建了MessageQueue,所以一个线程也只有一个MessageQueue
开始循环等待消息到来
Looper.loop();
public static void loop() {
//这里就是 final Looper me = sThreadLocal.get();
//找到此线程对应的Looper
final Looper me = myLooper();
//必须创建Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取MessageQueue对象
final MessageQueue queue = me.mQueue;
//for循环读取消息
for (;;) {
//MessageQueue中有消息就返回 没消息就阻塞
Message msg = queue.next();
if (msg == null) {
return;
}
//target是一个handler对象 此处分发了消息
msg.target.dispatchMessage(msg);
//回收
msg.recycleUnchecked();
}
}
收到消息后的处理
将消息对接给Handler 即dispatchMessage(Message msg);
public void dispatchMessage(Message msg) {
// callback不为空,则使用了post(Runnable r)发送消息
// 执行handleCallback(msg),即回调Runnable对象里复写的run()
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//若msg.callback属性为空,则使用了sendMessage发送消息
// 执行handleMessage(msg),即回调复写的handleMessage(msg)
handleMessage(msg);
}
}
Handler的创建
public Handler(Callback callback, boolean async) {
...
//绑定对应的looper、MessageQueue、callback
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler准备发送Message
发送Message有两种方式 也就是dispatchMessage(Message msg)中用来区分的
1.handler.post(Runnable runnable);
2.handler.sendMessage(Message msg);
- handler.post(Runnable runnable);
public final boolean post(Runnable r) {
//先是将runnable封装到Message中再send
//这里后续 在第二种方式里
return sendMessageDelayed(getPostMessage(r), 0);
}
//这里也是把runnable当做一个属性赋值给Message
//之后在dispatchMessage(Message msg)时 根据callback有无判断那种方式
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
- handler.sendMessage(msg);
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
//第一种也是调用这个方法
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//最终调用这个:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//将消息放入MessageQueue中
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//此处将Handler赋值给target
msg.target = this;
if (mAsynchronous) {
//设置消息异步,异步不会受同步障碍(某些操作会在消息队列引入同步障碍,防止后续消息传递确保无效请求在恢复前得到处理)的约束
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
将消息添加到MessageQueue中
MessageQueue.enqueueMessage(Message msg, long when);
boolean enqueueMessage(Message msg, long when) {
//检查消息是否有对应的Handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//检查消息是否已经被使用过
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//是否调用过MessageQueue.quit(boolean safe)方法退出
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
//标记已经使用了
msg.markInUse();
//消息目标发送时间 越小优先级越高
msg.when = when;
//获取头部消息
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//插入新的头部,如果阻塞就唤醒消息队列
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//将消息插入队列中
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 消息有同步屏障或者队列中有最早的异步消息 否则不需要唤醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
这样就把消息加入到消息队列中了,在这之后就回到前面Looper那边分发给Handler处理
看到这里再回头看看流程图和下面的总结会更好理解一些
注意要点
1.关于内存泄漏
- 采用静态内部类:static handler = xxx
- Activity结束时,调用handler.removeCallback()、然后handler设置为null
- 如果使用到Context等引用,要使用弱引用
2.MessageQueue其实是单链表数据结构主要是为了提高插入消息、删除消息的效率
3.一个线程最多只能有一个Looper
总结

最后
之前看了很多次关于这方面的知识,但总是感觉断断续续,模模糊糊,所以这次做一个小小的总结,留给以后回顾,如果文中如果有什么纰漏欢迎讨论与指出。
网友评论