handler 机制是 Android 实现异步的主要方式之一,特别适用于在子线程中进行数据操作,等数据处理完成后,使用 handler 进行 UI 操控。
handler的简单使用
/**
* 初始化 Handler 并重写 handleMessage 方法
*/
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("TAG", String.valueOf(msg.what));
}
};
//发送 Handler 消息
handler.sendEmptyMessage(1);
输出结果:
I/TAG: 1
分割线=================================================
基础概念
在讲源码前,先给大家输入一个基本概念:Handler 机制主要由 Handler、Message、MessageQueue、Looper 四部分组成。
- Handler :发送消息,异步回调。
- Message:消息体。
- MessageQueue:消息队列,存储 Handler 发送的消息。
- Looper:循环从 MessageQueue 里面获取消息,并调用 Handler 去执行 handleMessage 方法。
源码分析(源码只保留关键部分,并非全部源码)
new Handler()分析
首先,我们先从 new Handler()
开始看:
public Handler() {
this(null, false);
}
其实它调用的为
public Handler(Callback callback, boolean async) {
···
//初始化 Looper
mLooper = Looper.myLooper();
//若 mLooper 为 null,则抛出异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//赋值
mQueue = mLooper.mQueue; // final MessageQueue mQueue;
mCallback = callback;
mAsynchronous = async;
}
由此我们可以看出:new Handler()
的主要作用为初始化Handler
的同时,也初始化Handler
里面的Looper
和MessageQueue
对象。
我们来看看mLooper
是如何初始化的:Looper.myLooper();
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
直接从sThreadLocal
里面进行获取。ThreadLocal
里面还有一个set
方法,也就是将Looper
赋值到sThreadLocal
里面去,至于什么时候赋值的,我们暂时先不用管,只要知道这样new Hander()
的时候,一般情况下能够正常获取得到Looper
即可。
好了,new Hander()
的步骤我们大致清楚了,至于重写handleMessage
方法我们也可以先不用管,毕竟只是一个回调,我们先来看看handler.sendEmptyMessage(1)
。
sendEmptyMessage分析
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
经过重重传递后,会传递到
//将 what 封装到 msg 中
//uptimeMillis = SystemClock.uptimeMillis() + delayMillis
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//进行 mQueue 判断
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) {
//重点:this 为 当前的 handler,将 handler 引用赋值到 Message 里面
msg.target = this;
···
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
···
synchronized (this) {
···
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//将 msg 放入 MessageQueue 中
//这里的 when 其实就是之前的 uptimeMillis = SystemClock.uptimeMillis() + delayMillis
//在这里有个重点,就是 MessageQueue 的消息队列排序问题
//是以 when 的值大小进行排序,从小往大进行排序
if (p == null || when == 0 || when < p.when) {
// 若当前传过来的 msg 的 when 最小,则将其排在头部
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 根据当前 msg 的 when 大小进行插入排序
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) {
nativeWake(mPtr);
}
}
return true;
}
至此,Handler
的简单使用代码我们就讲完了,其中包含了 Handler、Message、MessageQueue。等等,Looper 不见?
Looper的创建以及循环遍历
其实是因为因为在ActivityThread
中的main(String[] args)
已经帮我们调用了 Looper 的创建以及 Looper 的循环遍历。
public static void main(String[] args) {
···
//初始化 Looper
Looper.prepareMainLooper();
···
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
···
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//循环遍历
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
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,并 set 到 sThreadLocal 中
//static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//sThreadLocal的作用就是使得每个线程都有自己独立 Looper,唯一,且互不干扰
sThreadLocal.set(new Looper(quitAllowed));
}
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.");
}
final MessageQueue queue = me.mQueue;
···
//开启死循环遍历
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
···
try {
//target 就是 handler 发送消息的时候,将自身引用存储到 message 中,其实就是发送message 的 handler
//通过 handler 去调用自身 dispatchMessage 方法
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
···
//消息回收
msg.recycleUnchecked();
}
}
public void dispatchMessage(Message msg) {
//优先处理 msg 里面的 callback
if (msg.callback != null) {
handleCallback(msg);
} else {
//其次处理创建 Handler 时传入的 mCallback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后才是调用 handleMessage
handleMessage(msg);
}
}
至此,Handler 的机制才是完成。 再次梳理下流程:
- Handler 发送 Message。
- Message 存储到 MessageQueue(以 when 的值大小进行排序)。
- Looper 循环遍历 MessageQueue。
- Looper 从 MessageQueue 中取出 Message。
- Looper 调用 Message 中的 Handler 去调用 Handler 的 dispatchMessage方法。
- dispatchMessage 方法里面包含 handleMessage 方法。
注意事项
在子线程使用 Handler 需要自己创建 Looper,并开启循环遍历
首先,我们先来一个错误的例子:
new Thread(new Runnable() {
@Override
public void run() {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("TAG", "收到消息" + msg.what);
}
};
handler.sendEmptyMessage(1);
}
}).start();
报错
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-16,5,main] that has not called Looper.prepare()
正确的方式如下所示:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("TAG", "收到消息" + msg.what);
}
};
handler.sendEmptyMessage(1);
Looper.loop();
handler.sendEmptyMessage(2);
Log.i("TAG", "测试能否输出日志");
}
}).start();
I/TAG: 收到消息1
等等,这两行代码怎么没有输出?
handler.sendEmptyMessage(2);
Log.i("TAG", "测试能否输出日志");
那时因为在调用Looper.loop();
的时候,已经开启的死循环,所以往后的代码都不会执行到了。
handleMessage所执行的线程不是创建Handler的线程,而是Looper所在的线程
这个很容易理解,因为通过上文,我们可知: 是 Looper 拿到 MessageQueue 的 Message 后,拿 Message 里面的 Handler 引用去调用 Handler 的 dispatchMessage方法,而 dispatchMessage 方法里面包含 handleMessage 方法。
简单来说
就是 Looper 在调用 handleMessage 方法。
这时,问题又来了,在最开始的 Handler 的简单使用中,并没有对于 Looper 操作,也就是在new Handler()
的时候,就默认将 Handler 与所在线程的 Looper 进行绑定,很容易让人认为 Handler 与其 Looper 一定在同个线程里面。
其实,Handler 的构造方法还有这个:
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这时,Handler 就可以与其他线程的 Looper 进行绑定。
Handler的handleMessage里面不一定可以进行UI操作
很多人对于 Handler 的了解,都是使用 Handler 进行 UI 操作。但是,由上文可知,handleMessage 是由 Looper 调用了,也就是说,只有ActivityThread
的Looper
才可以进行 UI 操作。至于子线程的Looper
都不行。
因此,假如我们需要在子线程使用 Handler 进行 UI 操作,可以这样做:
Handler handler = new Handler(Looper.getMainLooper());
网友评论