简介
作为一个Android开发者,Handler的大名你一定听过。做Android开发肯定离不开Handler,它通常被我们用来连通主线程和子线程。
可以说只要有异步的地方一定有Handler。
那么,你了解过为什么Handler能连通主线程和子线程吗,也就是说,你了解过Handler背后的原理吗?
就让本文带你了解。
Handler的基本用法
按照惯例,我们首先看下Handler的一般用法:
Handler mHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
// 在这里接受并处理消息
}
};
//发送消息
mHandler.sendMessage(message);
mHandler.post(runnable);
也就是创建一个Handler对象,并重写handlerMessage方法,然后在需要的时候调用sendMessage方法传入一个message对象,或者调用post方法传入一个runnable对象。
那么我们从他的构造方法开始看起吧。
从Handler构造方法入手
public Handler() {
// ->> 分析1.1
this(null, false);
}
分析1.1 Handler # 构造方法
/**
* 分析1.1:实际上调用的又是另一个构造方法
*/
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
// 这个变量字面意思是找到内存泄漏,
// 但是整个Handler中除了这块以及定义这个变量为false之外,
// 就没有其他地方使用到过这个变量了,所以这块我也不太懂这个变量是怎么变为true的
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());
}
}
// ->> 分析1.2
mLooper = Looper.myLooper();
// ->> 分析1.3
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 获取对象的mQueue属性,mQueue就是MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
分析1.2 Looper # myLooper()
/**
* 分析1.2:Looper.myLopper()
* 实际上调用的是ThreadLocal的get方法,然后返回该线程的Looper对象
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
ThreadLocal是一个数据存储类,他的特别之处在于他是线程间独立的,也就是说这个线程放入到ThreadLocal的数据,其它线程是获取不到的。sThreadLocal就是获取当前线程的Looper对象。详细可见我之前的博客。
分析1.3 Looper # prepare()
为什么说如果mLooper为空就抛异常呢,这是因为一个Handler必须和一个Looper绑定,并且要先初始化Looper才能去初始化Handler。初始化Looper就通过Looper的prepare方法。
/**
* 分析1.3:Looper.prepare()
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null