Android系统中的Java应用程序和其他系统上类似,都是靠消息驱动来工作的。他们都拥有一个消息队列,可以往队列中投递新消息,他们还有一个消息循环,用于不断地从队列中取出消息来处理。在Android系统中,这两项工作主要由Looper和Handler来实现。
Looper类分析
我们先从官方的一个例子来研究:
1 | class LooperThread extends Thread { |
根据官方文档的说明,在使用Looper的时候,我们得先调用Looper的prepare方法(第5行所示),然后再调用Looper的loop方法(第13行所示)。
我们先来看看Looper的prepare方法:
1 | /** Initialize the current thread as a looper. |
从注释我们可以得知这个方法是用来为当前线程初始化一个looper的。在第12行的sThreadLocal变量是一个当前线程局部变量,用于存储当前线程的某些值,拥有get和set两个重要方法。从代码我们可以得知,如果当前线程没有设置looper这个变量,那么prepare方法就会为其设置一个,如果有就会报错。接下来我们来看看Looper的构造函数:
1 | private Looper(boolean quitAllowed) { |
在构造函数中,looper首先构造了一个消息队列,然后得到了当前线程的对象。
总的来说Looper.prepare方法判断当前线程是否绑定了一个looper对象,如果没有就构造一个含有消息队列looper对象并绑定到当前线程上。
接下来我们来看看Looper的loop方法:
1 | public static void loop() { |
方法的第2行调用了myLooper方法,这个方法返回了当前线程持有的looper对象:
1 | public static Looper myLooper() { |
取得当前线程的looper对象后,方法获取了looper对象里面的消息队列,并进入一个循环开始处理消息。
综上所述,Looper的作用是:
1. 封装了一个消息队列
2. 使用Looper.prepare方法把looper对象与当前线程绑定在一起
3. 线程调用Looper.loop方法后,处理消息队列的消息
Handler类分析
接下来我们来看看Handler:
1 | public Handler(Callback callback, boolean async) { |
1 | public interface Callback { |
Handler类拥有多个构造函数,但最后都会调用上面这两个构造函数。第一个构造函数获取当前线程的looper对象,第二个构造函数获取传入参数的looper对象,然后获取保存looper对象的消息队列,同时保存了一个callback的回调接口,和一个布尔变量值表示是否异步。
由上面的方法我们知道,为什么调用Handler()之前一定要调用Looper.prepare方法了。
根据官方的文档所知,Handler类其实就是一个用来处理消息的辅助类,里面主要提供了这些方法:
1 | public void handleMessage(Message msg) |
对上面的方法稍作分析,我们就能明白其他方法,我们取sendMessage方法为例:
1 | public final boolean sendMessage(Message msg) |
从上面的方法我们可以发现,如果没有Handler的辅助,由我们自己来操作消息队列,是多么麻烦的一件事情!
Handler把Message的target设为自己,是因为Handler不仅封装了消息的发送,还封装了消息的处理。看回Looper.loop方法我们发现,最终消息的处理是在第19行:交给了Message对象的target的dispatchMessage方法实现,该方法如下所示:
1 | public void dispatchMessage(Message msg) { |
该方法定义了一套消息处理的优先级机制:
1. 如果Message自带了callback,则交给callback处理
2. 如果Handler设置了全局的mCallback,则交给mCallback处理
3. 如果上述都没有,则交给Handler子类实现的handleMessage方法处理
一般情况我们都会使用第三种处理方式,因此我们在构造handler对象的时候都会重写里面的handleMessage方法。
看完了消息的投递和处理,我们再来看看如何获取消息:
1 | public final Message obtainMessage() |
Handler类中的obtainMessage最终调用了Message类中的obtain方法,该方法首先判断在消息池中是否有可以回收的消息对象,如果有则使用可回收的消息对象,否则就新创建一个消息对象。通过调用该方法我们可以在多种情况下避免创建过多的消息对象,节省了内存空间。
综上所述,Looper类掌握着线程的消息队列,封装了消息循环;而Handler类则是消息处理的辅助类,里面封装了消息的投递、处理和获取等一系列操作。
HandlerThread的使用
我们考虑如下一段代码:
1 | public class MyActivity extends Activity { |
在代码中我们新建了一个新的线程,并通过为其设置绑定Looper从而在主线程使用Handler与该线程进行通信。
然而我们的代码是有错误的,了解多线程编程的同学应该知道,在并发编程中线程执行的顺序是不可预测的,因此在注释那一行构造Handler时传入的looper参数极有可能为null。
那么我们该如何解决这个问题呢?针对这个问题,Android官方已经为我们提供了一个HandlerThread类供我们使用,我们来看一下其中的关键代码:
1 |
|
HandlerThread提供了getLooper方法让我们获取构造线程的Looper对象,从上可以看出Google巧妙地使用了一对wait/notifyAll解决了我们的问题。因此以后要是我们的子线程需要使用Looper与Handler通信时,记得使用官方提供的HandlerThread即可。