Handler原理解析
Handler做为Android线程间通信的基础,是开发与面试必备技能。与之相关的有AsynTask,EventBus等
- 子线程中使用Handler与主线程通信
- 如何创建子线程自己的Handler来进行通信
- AsynTask,EventBus等对于Hangler的应用
一、子线程中使用Handler与主线程通信
1. Looper的初始化(主线程)
如果了解过应用启动流程的同学,应该知道ActivityThread的main方法才是应用的入口,在这里我们就不细说了。主线程的Looper对象,就是在ActivityThread的main方法中进行的初始化操作,Looper的初始化主要包含两步:
- 初始化looper对象
- looper开始轮询
public final class ActivityThread {
public static void main(String[] args) {
...
//1. 初始化looper对象
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//建立Binder通道 (创建新线程)
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 2. looper开始轮询
Looper.loop();
...
}
}
prepare方法创建了Looper对象,将主线程与Looper对象绑定,存入静态变量sThreadLocal对象中 ,并以sThreadLocal为key,Looper为value创建ThreadLocalMap,然后赋值给主线程的成员变量threadLocals。也就是说,prepare完成了主线程与Looper的绑定关系
public final class Looper {
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
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");
}
sThreadLocal.set(new Looper(quitAllowed));
}
...
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
这里我们看一下Looper的构造方法,创建了消息队列和当前线程变量,其中变量quitAllowed代表主线程的消息队列不允许停止
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
那么ThreadLocal内部怎么实现绑定线程与Handler的关系的呢?
在get()方法中,首先会获取当前的线程,以及其成员变量t.threadLocals,threadLocals是ThreadLocalMap类型,存储了当前线程相关联的所有的ThreadLocal对象,以及与之绑定的范型的实例,即Handler对象。如果获取到线程的threadLocals为空,或者threadLocals中保存的未保存当前ThreadLocal内部的Looper,则会继续执行setInitialValue()
setInitialValue()方法会调用
public class ThreadLocal {
// 1.步骤一,ActivityThread初始化Looper时会调用,然后执行createMap()
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 2.步骤一,以ThreadLocal为key,Looper为value创建了ThreadLocalMap,并赋值给主线程的局部变量
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// 3. 步骤二,在调用Looper.myLooper()时返回主线程绑定的Looper
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
}
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}
第二步操作Looper.loop()方法会获取与线程相关联的Looper,开启一个循环,不断的轮询looper内部消息队列中消息,并进行分发操作
思考:为何loop()方法不会阻塞主线程
public static void loop() {
final Looper me = myLooper();
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 {
msg.target.dispatchMessage(msg);
} finally {
}
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
2. Handler的创建与调用
handler(主线程)的创建步骤如下:
- 在主线程中使用new Handler()创建handler
- 子线程中使用handler.sendMessage(msg)发消息
- 在主线程的handler的handlerMessage中处理消息
主线程中创建Handler时,调用的是无参数构造方法,通过myLooper()获取到与当前线程绑定的looper对象
public class Handler {
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
}
发送消息时会调用sendMessage(msg)方法,最终会调用queue.enqueueMessage()将消息放入消息队列
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
...
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) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue调用enqueueMessage()时,将新消息加入消息队列,并且更新上一个消息和下一个消息
public final class MessageQueue {
Message mMessages;
//
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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);
}
}
}
}
此时因为主线程的looper的loop()方法一直处于等待执行,当接收到新消息时会分发消息
msg.target.dispatchMessage(msg),target为发送消息的Handler对象,handler会调用
初始化Handler时复写的handleMessage(msg)方法,将msg传出
public void dispatchMessage(Message msg) {
...
handleMessage(msg);
}
//实现为空
public void handleMessage(Message msg) {
}
二、如何创建子线程自己的Handler来进行通信
在主线程中,我们调用了无参数的Handler构造方法,如果在子线程中调用,就会抛出RuntimeException异常,因为我们没有初始化Handler相关的Looper对象。那么子线程中我们需要自己初始化looper,然后调用有参构造方法创建Handler
public class MyHandlerThread extends Thread{
Looper looper = null;
@Override
public void run(){
Looper.prepare();
looper.loop();
}
}
//调用方法
public void init(){
MyHandlerThread handlerThread = new MyHandlerThread();
handlerThread.start();
Handler threadHandler = new Handler(handlerThread.looper){
@Override
public void handleMessage(Message msg){
}
};
threadHandler.sendMessage(msg);
}
其实google已经帮我们实现了以上操作,HandlerThread的run方法中会调用Looper.prepare()与Looper.loop();创建当前的线程相关的Looper
public class HandlerThread extends Thread {
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
}