对Handler机制的理解
前言
Handeler机制算是Android中一个比较核心的内容了,本文是经过对Handler源码的分析做的一个总结。
目录
主要从以下几个方面来总结:
- Handler机制简介
- 核心类以及作用
- Handler工作流程
- 源码分析
Handler机制简介
Handler机制是一套消息传递机制,在Android的多线程开发场景中会经常使用,实现的功能是多线程之间的通信。由于Android的UI操作不是线程安全的,所以在子线程中主要是通过Handler来对UI操作。
核心类以及作用
Handler机制由Handler、Looper、MessageQueue和Message构成。
-
Handler
Handler类两个作用,发送消息和处理消息。
-
MessageQueue
MessageQueue用来维护消息队列,根据时间将消息放入队列和将消息移除队列。
-
Looper
以死循环的方式不断从MessageQueue中获取消息,分发消息。
-
Message
消息的承载者
工作流程
工作流程主要分为4步:
-
核心类初始化
为当前线程创建Looper,MessageQueue,即调用静态方法Looper.prepare(),然后创建Handler对象(有多个重载的构造方法,可以指定Looper,默认是当前线程的Looper),启动循环Looper.loop().
-
发送消息
通过Handler的sendMessage和post方法发送消息,将消息加入到消息队列。
-
消息循环
Lopper不停通过循环,从MessageQueue中拿到Message,然后调用与Message绑定的Handler来分发消息(handler.dispatchMessage(Message msg)),具体分发逻辑会在后文讲到。
-
消息处理
Handler的dispatchMessage方法被调用后,会选择执行具体的消息处理逻辑。
注意事项:Thread、Handler、MessageQueue和Looper的对应关系。
- 一个Thread只能绑定一个Looper,一个MessageQueue,多个Handler。
- 一个Looper只能绑定一个MessageQueue,多个Handler
- 一个Handler只能绑定一个Looper和一个MessageQueque
源码分析
这一部分主要是分析核心类的构造方法和主要方法,来提高对Handler机制细节方面的认识。
Looper类
先看构造方法:
//私有构造方法,参数表示是否允许退出循环,
private Looper(boolean quitAllowed) {
//创建消息队列,保存当前线程,参数由MessageQueue接收,可见退出逻辑应该在MessageQueue中实现
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//子线程Looper初始化
public static void prepare() {
//子线程允许退出
prepare(true);
}
//在此方法中创建Looper
private static void prepare(boolean quitAllowed) {
//检查当前线程是否已有Looper,每个线程只能执行一次,否则将会抛出异常,即一个线程只能有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper,并保存在当前线程中
sThreadLocal.set(new Looper(quitAllowed));
}
//主线程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();
}
}
//获取当前线程的Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//判断当前线程是不是运行在与Looper关联的线程中
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
//在任何地方都可通过此方法获取主线程的Looper对象
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
上面列出了Looper的构造方法以及和构造方法相关的几个方法,由分析可知:
- Looper的构造方法是私有的,只能通过静态方法*prepare()和prepareMainLooper()为当前线程创建Looper。
- 创建Looper的时候就会创建MessageQueue,并绑定MessageQueue和Thread实例。
- 主线程不允许退出,子线程可以退出,退出逻辑在MessageQueue中实现。
- 创建的Looper实例通过ThreadLocal被保存在当前线程中。(需要知道:ThreadLocal可以将对象保存在当前线程中,并且也可以从当前线程中获取之前保存的对象,至于具体实现这里不在赘述)
循环方法分析:
public static void loop() {
//这里要注意prepare()和loop()的调用顺序,以及要确定在调用此方法的线程中是否有Looper,否则会抛出异常
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//拿到消息队列
final MessageQueue queue = me.mQueue;
//开始循环读取消息队列中的消息
for (;;) {
//在队列中没有消息时,会阻塞线程
Message msg = queue.next(); // might block
//退出消息循环的时机是在消息队列返回Null值时
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
//将消息交给与消息绑定的handler处理,也就是发送这条消息的Handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//回收消息
msg.recycleUnchecked();
}
}
Handler类
从以下三个方面来分析源码:
- 构造方法
- 发送消息
- 处理消息
构造方法
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Callback callback, boolean async) {
//继承Handler时,若没有用static修饰,可能会造成内存泄漏
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());
}
}
//在子线程中直接使用new Handler()会抛出异常的原因:没有创建Looper
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;
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
/**
*@param looper 指定与handler绑定的Looper
*@param callback Handler中定义的接口,只有一个handleMessage(Message msg)方法
*@param async 只有系统创建Handler会用到这个参数,表示由此Handler发送的消息是否要标记为异步消息
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
从上面可以知道,Handler的构造方法有很多个重载,但是我们能调用的方法只有三个,其他的都被用@hide注解,只有sdk能调用。
- Handler()
- Handler(Callback callback)
- Handler(Looper looper)
通过构造方法可以总结两点:
- 在继承Handler时,需要注意可能发生的内存泄漏
- 子线程在没有调用Looper.prepare()时,除了Handler(Looper looper),其他两个构造方法不能调用,否则会抛出异常。
发送消息
发送消息有两种方式
- sendMessage:发送一个Message对象
- post:发送一个Runnable,Runnable最终会被包装成Message对象
//包装Runnable
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
//消息最终都是通过这个方法发送
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;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
//直接将消息放在消息队列头部,优先处理,可能有副作用
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
//将消息加入到消息队列中
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//将消息与当前Handler绑定
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
处理消息
//分发消息,由Looper调用
public void dispatchMessage(Message msg) {
//先判断是否是post的消息,
if (msg.callback != null) {
handleCallback(msg);
} else {
//在判断当前Handler是否设置CallBack,构造方法有说到
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后才调用Handler的成员方法
handleMessage(msg);
}
}
MessageQueue类
MessageQueue用于维护消息队列,主要有两种操作:
- 将消息加入到消息队列
- 将消息移除消息队列
将消息加入到消息队列:
boolean enqueueMessage(Message msg, long when) {
...省略
synchronized (this) {
...省略
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//当前是空队列or消息是通过sendMessageAtFrontOfQueue发送或时间小于队列第一个消息的时间,则将msg置于队列头部
//若当前是阻塞状态,需要唤醒线程
// New head, wake up the event queue if blocked.
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//调用native方法,唤醒线程
nativeWake(mPtr);
}
}
return true;
}
注意:消息队列虽然是一个队列,但并不完全遵循先入先出的规则,消息在入队时,会遍历链表,比较每一个消息的时间,按时间排序
将消息移除消息队列:
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//
int nextPollTimeoutMillis = 0;
//死循环
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//nextPollTimeoutMillis不为0时,阻塞线程
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) {
//这里也有一个循环,用来找到下一个要处理的message
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;
}
//若当前处于退出状态,返回null
if (mQuitting) {
dispose();
return null;
}
...省略
}
}
至此,对Handler机制的源码分析完毕,通过阅读这些源码,对Handler机制的实现细节有了一个更深的认识。