这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
熟悉又陌生的Handler-1
Handler三件套的创建流程:
构造方法如下:
public Handler(Callback callback, boolean async) {
// 如果这个flag是true
// 会在运行时检测Handler的实现是不是静态的(匿名内 || 内部类 || 局部类)
// 会在运行时输出wraning提示可能造成内存泄漏
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());
}
}
// 如果在调用Handler构造方法的时候,没有获取到当前所在线程的Looper对象
// 直接抛出异常,因为这种状态下的Handler完全不可用
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 让当前Handler也持有当前线程的Looper的MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
// 标识这个Handler发送的Message是否都是异步消息(作用后面再分析)
mAsynchronous = async;
}
复制代码
而对于主线程而言,Looper的创建是在ActivityThread.main中完成的,通过调用prepareMainLooper:
public static void prepareMainLooper() {
// 也是通过调用Looper.prepare进行创建,只不过quitAllowed设置为false
// 表示这个Looper永远不会主动退出
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 将主线程的Looper对象引用赋值给sMainLooper这个静态变量
sMainLooper = myLooper();
}
}
复制代码
Looper的创建都是通过调用prepare方法(如果我们需要自己创建一个Handler-Looper也一样是调用Looper.prepare这个静态方法):
// Looper对外暴露的prepare方法创建的Looper是会主动退出的
public static void prepare() {
prepare(true);
}
// 这个静态方法只对内提供,
// 即quitAllowed=false只在创建主线程的Looper的时候允许
private static void prepare(boolean quitAllowed) {
// sThreadLocal是一个线程唯一的容器,这里存放的是Looper对象
// 如果当前线程已经创建过了Looper,再次调用prepare会报错
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 创建一个Looper对象并存入sThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
复制代码
而在Looper的构造函数中,只做了两件事:
private Looper(boolean quitAllowed) {
// 创建MessageQueue对象
mQueue = new MessageQueue(quitAllowed);
// 获取当前的线程实例
mThread = Thread.currentThread();
}
复制代码
而MessageQueue的构造,最主要的还是调用nativeInit完成Native侧的初始化工作,这个后面再做分析。
那我们先简单做个小结:
上面我们涉及到了几个对象:Handler,Looper,MessageQueue。这三个对象的作用,众所周知……
- Handler:负责消息的发送和处理。
- MessageQueue:存放Message对象的队列,本质上就是一个数据结构。
- Looper:三件套的驱动,不断从消息队列中取消息然后发送给对应的Handler。
上面提到了一个Message对象,后面再分析,本质上也不过是一个存放一些数据的数据结构。
Looper.loop启动Looper的钥匙:
如果我们仅仅是构造了Handler和Looper对象,去发送消息,会发现整个系统并没有被运转起来,因为我们没有调用Looper.loop方法开启MessageQueue的循环。
在ActivityThread的main方法中,在创建了主线程的Looper之后,会调用Looper.loop开启消息循环,所以我们如果在主线程中创建的Handler,不需要调用什么其它Api,直接就可以发送消息了。
Looper.loop代码如下:
public static void loop() {
// 依旧是做一些必须的校验工作
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 当前Looper的消息队列
final MessageQueue queue = me.mQueue;
// ...
// 一个无限循环,来不停的消费队列中的Message对象
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// 当消息队列中没有任何消息了,退出循环
return
}
// 省略一些trace相关的代码
try {
// 将消息分发给对应的target
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
// 省略一些log等代码
// message是复用的,一个消息分发完了,之后进行资源回收工作
msg.recycleUnchecked();
}
}
复制代码
可以看到Looper.loop做的最核心的两件事:
- 驱动循环不停从MessageQueue中取Message。
- 将Message分发给Message.target。
Message等待被消费的数据
Message.target是什么呢?
我们要发送一个消息,调用的API都是:Hander.postXXX或者Handler.sendXXX系列的API。postXXX表示发送一个Runnable,前者postXXX系列API都是基于后者系列sendXXX实现的,postXXX发送出去的Runnable最终还是封装成了Message(Message.callback成员)。
Message的创建,在真正调用send系列API之前,大多都会有如下操作:
// 因为进程中可能会有大量消息的场景,为了实现对象复用
Message m = Message.obtain();
// obtain如下:
public static Message obtain() {
// sPoolSync是一个Object,这里用作Lock
synchronized (sPoolSync) {
// 以链表的形式,存放所有的Message缓存
// 需要的时候,再从链表头一个一个取。
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
// 如果队列中没有,再做重新创建,在一个Message被Looper.loop分发消费完了之后
// 会进行相应的回收工作。
return new Message();
}
复制代码
最终,Message的发送,都是在sendMessageAtTime这个API:
// Message是要发送的消息对象,uptimeMillis表示这个消息需要被处理的时间
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);
}
// 将消息入队列:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 而这里的target,就是发送这个消息的Handler。
msg.target = this;
// 如果Handler构造方法中设置了这个Handler发送的都是异步消息
// 这里会将Message对象标记为是异步Message,作用后面再分析。
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码
如上述代码,Handler将自己和所要传递的信息或者任务(Runnable)打包到了Message中,然后调用MessageQueue的入队列方法,将消息入队列。
那么这里清楚了,Message.target实际上就是Handler自己,Handler的dispatch方法如下:
public void dispatchMessage(Message msg) {
// 如果是发送一个runnable,那么会调用runnable.run跑要执行的任务
if (msg.callback != null) {
handleCallback(msg);
} else {
// 如果在创建Handler的时候传入了callback字段
// 那么消息的消费会被传递给callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 否则,调用等待子类重写的handleMessage,将消息
// 交给Handler的具体子类去处理。
handleMessage(msg);
}
}
复制代码