Handler可以说是android开发面试毕问的一道题了,所以我本人也会经常看一些相关的文章,写这片文章的用意既是给自己看的,同时也想分享给那些对Handler不是太了解朋友们(大神请绕道),好啦,那么进入正题吧。
想要了解handler机制那么我们先要知道它的作用,大家都知道在android中,UI线程是非线程安全的,也就是更新UI只能在UI线程中完成,其他工作线程无法直接操作UI线程。耗时操作要在工作线程中完成(不能阻塞主线程)。为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁。
相信看完上面的话大家对handler有了个大概的了解,我们再来看看Handler 、 Looper 、Message 这三者的关系
我们首先看一下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我们总结一下吧
首先Looper.prepare()保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次否则会抛异常,所以MessageQueue在一个线程中只会存在一个。Looper.loop()会让当前线程进入一个无限循环(如果没有消息则阻塞),不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
注:
程序的主线程中会始终存在一个Looper对象,从而不需要再手动去调用Looper.prepare()方法了。而在子线程中需要先调用Looper.prepare()才能创建Handler对象。