Handler,Message,MessageQueue,Looper,是android一种消息处理机制,在android开发中经常会用到,当Handler创建后,会被绑定到它所在的线程上,处理消息的成员及其功能如下:
Handler:发送一个消息(Message)去做特定任务
Message:代表一个要处理的任务;
MessageQueue:Message的队列;
Looper:负责循环Message队列,取出Message又传给Handler处理。
它们之间关系如下:
每个线程中只有一个Looper,由ThreadLocal维护;
每个Looper中只有一个MessageQueue,因此一个线程中只有一个MessageQueue;
每个MessageQueue中可以有多个Message;
每个线程中可以有多个Handler;
四者关系如下图:
接下来我们以开发中使用时的顺序来分析它们之间的关系。
1.Looper
Looper,就是不断循环读取消息给Handler。在开发过程中,更多的是在主线程中对Handler进行实例化,然后就可以调用sendMessage()方法发送消息了,不需要对Looper做额外的处理,但是如果我们在子线程进行实例化Handler时,则必须在实例化Handler之前对Looper做如下的操作:
class MyThread extends Thread{
@Override
public void run() {
//为该线程创建一个Looper
Looper.prepare();
//实例化Handler
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//不断循环读取Message
Looper.loop();
}
}
至于为什么在子线程中必须进行这样的操作,而在主线程就不需要这样的操作呢?这就先得从
Handler
说起了。
1.1.子线程中Looper的获取
Handler的构造方法如下:
public Handler() {
this(null, false);
}
直接看它另一个重载构造方法:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
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());
}
}
//获取当前线程的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这里很明显了,在Handler实例化时,会首先获取当前线程的Looper,如果不存在Looper,则抛出Runtime异常,注意了,这里是”当前线程”,这是什么意思?下面进行分析。
再来看看Looper中的两个静态方法干了什么,prepare()方法如下:
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));
}
在prepare()方法中,获取了Looper对象,并且维护了一个ThreadLocal存放每个线程的Looper对象,通过ThreadLocal将线程和Looper进行了绑定,从而解决了多线程问题,保证了每个线程只有一个Looper对象。因此,如果在子线程中不显示调用prepare()方法,则由于该线程中没有Looper对象,从而报出异常:Can't create handler inside thread that has