想要了解handler机制那么我们先要知道它的作用,大家都知道在android中,UI线程是非线程安全的,也就是更新UI只能在UI线程中完成,其他工作线程无法直接操作UI线程。耗时操作要在工作线程中完成(不能阻塞主线程)。为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁。
相信看完上面的话大家对handler有了个大概的了解,我们再来看看Handler 、 Looper 、Message 这三者与Android异步消息处理线程相关的概念。那么什么叫异步消息处理线程呢?
异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。
说了这一堆,那么和Handler 、 Looper 、Message有啥关系?其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。
我们首先看一下looper的prepare()方法。
prepare()方法
public static final void prepare() {
if(sThreadLocal.get() !=null) {
thrownewRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(newLooper(true));
}
从代码中我们可以看出 将一个looper的对象放入到sThreadLocal当中,并且sThreadLocal如果不为空就抛出异常,那么说明prepare()被重复调用就会抛出异常,那么也就是一个线程中只有一个looper实例。
我们再来看一下looper的构造方法
private Looper(boolean quitAllowed) {
mQueue =new MessageQueue(quitAllowed);
mRun =true;
mThread = Thread.currentThread();
}
我们可以看到构造looper 被初始化的同时也会初始化一个MessageQueue(消息队列)
我们再来看一下loop()方法
public static void loop() {
finalLooper me = myLooper();
if(me ==null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final longident = Binder.clearCallingIdentity();
for(;;) {
Message msg = queue.next();// might block
if(msg ==null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if(logging !=null) {
logging.println(">>>>> Dispatching to "+ msg.target +" "+
msg.callback +": "+ msg.what);
}
msg.target.dispatchMessage(msg);
if(logging !=null) {
logging.println("<<<<< Finished to "+ msg.target +" "+ msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final longnewIdent = Binder.clearCallingIdentity();
if(ident != newIdent) {
Log.wtf(TAG,"Thread identity changed from 0x"
+ Long.toHexString(ident) +" to 0x"
+ Long.toHexString(newIdent) +" while dispatching to "
+ msg.target.getClass().getName() +" "
+ msg.callback +" what="+ msg.what);
}
msg.recycle();
}
}
myLooper()这个方法返回的Looper实例,如果me为null则抛出异常,也就是说looper方法必须在prepare方法之后运行。
me.mQueue拿到该looper实例中的mQueue(消息队列),在for循环 这个方法Message msg = queue.next();里取出一条消息,如果没有消息则阻塞。
调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理消息,target其实就是Handler实例
looper介绍完了,我们再来看看Handler
public Handler() {
this(null,false);
}
public Handler(Callback callback,booleanasync) {
if(FIND_POTENTIAL_LEAKS) {
finalClass 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());
}
}
mLooper = Looper.myLooper();
if(mLooper ==null) {
thrownewRuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在mQueue = mLooper.mQueue;又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。
了解完了looper和handler我们总结一下吧
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环(如果没有消息则阻塞),不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
总结完毕.