Handler源码分析
Android异步消息处理机制完全解析,带你从源码的角度彻底理解(郭霖)
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系(鸿洋)
一、Handler基本使用
Handler是Android中最常用的了,主要作用无非就是用来解决子线程中无法更新UI的问题,一般在子线程中获取到的数据,可以通过Handler发送到主线程中然后进行UI操作,所以在分析Hanlder的时候,还是有必要先看一下Handler的基本使用步骤。代码如下:
public class TestActivity extends Activity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private Handler threadHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
new Thread(new Runnable() {
@Override
public void run() {
threadHandler = new Handler();
mHandler.sendMessage(new Message());
}
}).start();
}
}
上面代码中在主线程和子线程中分别创建了一个Hanlder,看上去这段代码是没什么问题,但其实运行的时候会报错,java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-4,5,main] that has not called Looper.prepare()
,这里表示无法在子线程中创建Handler,因为子线程中在创建Handler的时候没有调用Looper.prepare(),那么接下来我们在子线程中加上Looper.prepare()试试,如下:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
threadHandler = new Handler();
mHandler.sendMessage(new Message());
}
}).start();
这时程序就能正常运行了。这里需要知道,一个线程中如果要创建Handler,那么在实例化Hanler之前需要调用Looper.prepare()。那么这里大家可能会有一个疑问,那就是为什么主线程中不需要调用Looper.prepare()呢?
这是因为我们应用在启动的时候会执行ActivityThread中的main()方法,而main()方法中调用了Looper.prepareMainLooper();
,点击进去继续查看源码可以发现Looper.prepareMainLooper()
方法调用的就是prepare()方法,这里即表明主线程在初始化的时候就调用了Looper.prepare()方法。知道了这些,我们接下来可以分析来分析Handler的源码了。其实一说到分析Handler源码,那必然是离不开Message,Looper,MessageQueue这几个类的源码的。
二、源码分析(Handler、Looper、MessageQueue之间的关系)
通过上面的一个流程我们知道在创建Handler之前需要先调用Looper.prepare()方法,那么我们首先来看看Looper.prepare()这个方法的源码到底是什么?
public static void prepare() {
prepare(true);
}
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));
}
Looper的prepare方法调用了一个重载方法,那么接下来我们就该看看sThreadLocal是什么东西了。
Android的消息机制之ThreadLocal的工作原理
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal的set于get方法和map的set,get方法类似,这里然后分析
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));
}
,首先判断sThreadLocal.get()获取到的Looper是否为空,不为空则抛出异常,否则创建一个Looper保存,那么从这里我们可以看出来在一个线程中Looper.prepare()方法只能够掉一次,如果调用了一次以上则会抛出异常。
好了,Looper.prepare()方法就说到这,接着往下看,在执行完,Looper.prepare()方法后,我们可以创建一个Handler,那这里我们看一下Handler的构造函数源码
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;
}
上面只列出了主要代码,我们一行