Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler来投递消息到主线程执行UI更新操作。因为Android系统的View是非线程安全的,所以需要在主线程更新UI。总的来说Handler就是用来做线程间通信,在不同线程之间传递消息。注:这篇文章所讲到的Handler是在主线程创建的,主线程在开始的时候已经创建了默认的消息循环。后面的文章会讲如何创建自己的消息循环。

Handler Looper原理图
从图中可以看出,四种颜色分别代表了四个对象,并且大致描述了几个对象之间的关系,以及消息的流转过程,首先Handler通过sendMessage将消息投递给MessageQueue,Looper通过消息循环(loop)不断的从MessageQueue中取出消息,然后消息被Handler的dispatchMessage分发到handleMessage方法消费掉。通过Handler的sendMessage等方法来投递消息到MessageQueue,通过handleMessage来消费Message。Handler必须要有一个已经PRepare好的Looper对象,也就是说必须调用了prepare方法(也包括prepareMainLooper方法),究其根本是初始化一个消息队列,这一过程将在下文中详细分析。
Looper负责从MessageQueue中取出消息,然后通过执行message.target.dispatchMessage()消费掉这个消息,这里的target就是Handler。
消息队列,管理Handler投递过来的消息。
用来承载数据的消息,最终被Handler消费掉。

Handler class diagram
通过上面的类图可以清晰的了解各个类之间的关系。然后再来分析一下源码。| 12345678910111213141516171819 | publicHandler(Callbackcallback,booleanasync){ if(FIND_POTENTIAL_LEAKS){ finalClass<?extendsHandler>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;} |
| 1234567891011121314151617181920212223242526 | publicstaticvoidprepare(){ prepare(true);}public staticvoidprepareMainLooper(){ prepare(false); synchronized(Looper.class){ if(sMainLooper!=null){ thrownewIllegalStateException("The main Looper has already been prepared."); } sMainLooper=myLooper(); }} private staticvoidprepare(booleanquitAllowed){ if(sThreadLocal.get()!=null){ thrownewRuntimeException("Only one Looper may be created per thread"); } 将looper对象装入ThreadLocal中,Handler就是从它里面取出looper对象的 sThreadLocal.set(newLooper(quitAllowed));} private Looper(booleanquitAllowed){ //创建消息队列 mQueue=newMessageQueue(quitAllowed); mThread=Thread.currentThread();} |
看上面的关键代码,UI线程在创建的时候,会调用prepareMainLooper()这个方法,创建一个不退出的消息队列。所以prepareMainLooper这个方法自己永远也不要调用,它是系统调用的,如果我们需要用自己的消息队列呢?那么就应该调用prepare()方法。
整个消息循环系统中的几个重要部件的创建都已经明白了,那么消息时怎么循环起来的,又是如何消费的呢?来看看下面是loop源码的一部分关键代码。代码非常简单易懂,就是从消息队列中取出消息,然后通过msg.target.dispatchMessage(msg)将消息投递到Handler。
Java| 123456789101112131415161718 | publicstaticvoidloop(){ finalLooperme=myLooper(); if(me==null){ thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } finalMessageQueuequeue=me.mQueue; Binder.clearCallingIdentity(); finallongident=Binder.clearCallingIdentity(); for(;;){ Message msg=queue.next();// might block if(msg==null){ // No message indicates that the message queue is quitting. return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); } } |
| 123456789101112 | publicvoiddispatchMessage(Messagemsg){ if(msg.callback!=null){ handleCallback(msg); }else{ if(mCallback!=null){ if(mCallback.handleMessage(msg)){ return; } } handleMessage(msg); }} |
当消息循环中取出的消息被再次传递给Handler的时候,这个消息就走到了生命的尽头(并不代表对象销毁,有一个消息池来回收消息),从dispatchMessage方法可以看出,消息最终的归宿有三个,一是消息自身的callback接口,二是handler的callback接口,最后是handleMessage接口。
通过前面从不同方向对Android的Handler消息循环进行分析,基本结构和原理已经清晰,但是还远远不够,在接下来的文章中,将会对前面提到的潜质内存泄漏做一个详细的分析。转载自:vjson.com
新闻热点
疑难解答