android的消息队列机制
android下的线程,Looper线程,MessageQueue,Handler,Message等之间的关系,以及Message的send/post及Message dispatch的过程。
Looper线程
我们知道,线程是进程中某个单一顺序的控制流,它是内核做CPU调度的单位。那何为Looper线程呢?所谓Looper线程,即是借助于Looper和MessageQueue来管理控制流的一类线程。在android系统中,app的主线程即是借助于Looper和MessageQueue来管理控制流的,因而主线就是一个特殊的Looper线程。其实,不仅仅只有主线程可以用Looper和MessageQueue来管理控制流,其它的线程也一样可以。我们可以先看一下android源代码(Looper类,位置为frameworks/base/core/java/android/os/Looper.java)的注释中给出的一种Looper线程的实现方式:
packagecom.example.messagequeuedemo;importandroid.os.Handler;importandroid.os.Looper;importandroid.util.Log;publicclassLooperThreadextendsThread{publicstaticfinalStringTAG=MainActivity.TAG;privatestaticfinalStringCompTAG="LooperThread";publicHandlermHandler;@Overridepublicvoidrun(){Log.d(TAG,CompTAG+":LooperThread=>run");Looper.prepare();mHandler=newHandler(){publicvoidhandleMessage(android.os.Messagemsg){Log.d(TAG,CompTAG+":LooperThread=>Handler=>handleMessage");//processincomingmessagehere}};Looper.loop();}}
可以看到,就是在线程的run()方法中,调用Looper.prepare()做一些初始化,然后创建一个Handler对象,最后执行Looper.loop()启动整个的事件循环。就是这么简单的几行代码,一个可以使用消息队列来管理线程执行流程的Looper 线程就创建好了。
那么上面的每一行代码,具体又都做了些什么呢?接着我们就先来看下,神秘的Looper.prepare()到底都干了些什么:
//sThreadLocal.get()willreturnnullunlessyou'vecalledprepare().staticfinalThreadLocal<Looper>sThreadLocal=newThreadLocal<Looper>();/**Initializethecurrentthreadasalooper.*Thisgivesyouachancetocreatehandlersthatthenreference*thislooper,beforeactuallystartingtheloop.Besuretocall*{@link#loop()}aftercallingthismethod,andenditbycalling*{@link#quit()}.*/publicstaticvoidprepare(){prepare(true);}privatestaticvoidprepare(booleanquitAllowed){if(sThreadLocal.get()!=null){thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");}sThreadLocal.set(newLooper(quitAllowed));}privateLooper(booleanquitAllowed){mQueue=newMessageQueue(quitAllowed);mRun=true;mThread=Thread.currentThread();}
由这段代码可知,Looper.prepare()是一个静态方法,它做的事情就是简单地为当前的线程创建一个Looper对象,并存储在一个静态的线程局部存储变量中。在Looper的构造函数中又创建了一个MessageQueue对象。同时Looper会引用到当前的线程,并将一个表示执行状态的变量mRun设置为true。对于此处的线程局部存储变量sThreadLocal,可以简单地理解为一个HashMap,该HashMap中存放的数据其类型为Looper,key则为Thread,而每个线程又都只能获得特定于这个线程的key,从而访问到专属于这个线程的数据。
启动Looper线程就和启动普通的线程一样,比如:
publicclassMainActivityextendsActivity{publicstaticfinalStringTAG="MessageQueueDemo";privatestaticfinalStringCompTAG="MainActivity";privateLooperThreadmLooperThread;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){Log.d(TAG,CompTAG+":MainActivity=>onCreate");super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mLooperThread=newLooperThread();mLooperThread.start();}
同样是new一个对象,然后调用该对象的start()方法。
Android SDK本身也提供了一个class来实现LooperThread那样的机制,以方便在app中创建一个执行事件处理循环的后台线程,但提供的功能要完善得多,这个class就是HandlerThread。我们可以看一下这个class的定义:
packageandroid.os;/***Handyclassforstartinganewthreadthathasalooper.Theloopercanthenbe*usedtocreatehandlerclasses.Notethatstart()muststillbecalled.*/publicclassHandlerThreadextendsThread{intmPriority;intmTid=-1;LoopermLooper;publicHandlerThread(Stringname){super(name);mPriority=Process.THREAD_PRIORITY_DEFAULT;}/***ConstructsaHandlerThread.*@paramname*@parampriorityTheprioritytorunthethreadat.Thevaluesuppliedmustbefrom*{@linkandroid.os.Process}andnotfromjava.lang.Thread.*/publicHandlerThread(Stringname,intpriority){super(name);mPriority=priority;}/***Callbackmethodthatcanbeexplicitlyoverriddenifneededtoexecutesome*setupbeforeLooperloops.*/protectedvoidonLooperPrepared(){}@Overridepublicvoidrun(){mTid=Process.myTid();Looper.prepare();synchronized(this){mLooper=Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid=-1;}/***ThismethodreturnstheLooperassociatedwiththisthread.Ifthisthreadnotbeenstarted*orforanyreasonisisAlive()returnsfalse,thismethodwillreturnnull.Ifthisthread*hasbeenstarted,thismethodwillblockuntilthelooperhasbeeninitialized.*@returnThelooper.*/publicLoopergetLooper(){if(!isAlive()){returnnull;}//Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated.synchronized(this){while(isAlive()&&mLooper==null){try{wait();}catch(InterruptedExceptione){}}}returnmLooper;}/***Quitsthehandlerthread'slooper.*<p>*Causesthehandlerthread'sloopertoterminatewithoutprocessingany*moremessagesinthemessagequeue.*</p><p>*Anyattempttopostmessagestothequeueafterthelooperisaskedtoquitwillfail.*Forexample,the{@linkHandler#sendMessage(Message)}methodwillreturnfalse.*</p><pclass="note">*Usingthismethodmaybeunsafebecausesomemessagesmaynotbedelivered*beforethelooperterminates.Considerusing{@link#quitSafely}insteadtoensure*thatallpendingworkiscompletedinanorderlymanner.*</p>**@returnTrueifthelooperlooperhasbeenaskedtoquitorfalseifthe*threadhadnotyetstartedrunning.**@see#quitSafely*/publicbooleanquit(){Looperlooper=getLooper();if(looper!=null){looper.quit();returntrue;}returnfalse;}/***Quitsthehandlerthread'sloopersafely.*<p>*Causesthehandlerthread'sloopertoterminateassoonasallremainingmessages*inthemessagequeuethatarealreadyduetobedeliveredhavebeenhandled.*Pendingdelayedmessageswithduetimesinthefuturewillnotbedelivered.*</p><p>*Anyattempttopostmessagestothequeueafterthelooperisaskedtoquitwillfail.*Forexample,the{@linkHandler#sendMessage(Message)}methodwillreturnfalse.*</p><p>*Ifthethreadhasnotbeenstartedorhasfinished(thatisif*{@link#getLooper}returnsnull),thenfalseisreturned.*Otherwisethelooperisaskedtoquitandtrueisreturned.*</p>**@returnTrueifthelooperlooperhasbeenaskedtoquitorfalseifthe*threadhadnotyetstartedrunning.*/publicbooleanquitSafely(){Looperlooper=getLooper();if(looper!=null){looper.quitSafely();returntrue;}returnfalse;}/***Returnstheidentifierofthisthread.SeeProcess.myTid().*/publicintgetThreadId(){returnmTid;}}
它不仅有事件处理循环,还给app提供了灵活地设置HandlerThread的线程优先级的方法;事件循环实际启动前的回调(onLooperPrepared());获取HandlerThread的Looper的方法(这个方法对于Handler比较重要);以及多种停掉HandlerThread的方法——quit()和quitSafely()——以避免资源的leak。
Looper线程有两种,一种是我们上面看到的那种由app自己创建,并在后台运行的类型;另外一种则是android Java应用的主线程。创建前者的Looper对象需要使用Looper.prepare()方法,而创建后者的,则需使用Looper.prepareMainLooper()方法。我们可以看一下Looper.prepareMainLooper()的实现:
/***Initializethecurrentthreadasalooper,markingitasan*application'smainlooper.Themainlooperforyourapplication*iscreatedbytheAndroidenvironment,soyoushouldneverneed*tocallthisfunctionyourself.Seealso:{@link#prepare()}*/publicstaticvoidprepareMainLooper(){prepare(false);synchronized(Looper.class){if(sMainLooper!=null){thrownewIllegalStateException("ThemainLooperhasalreadybeenprepared.");}sMainLooper=myLooper();}}
比较特别的地方即在于,此处调用prepare()方法传进去的quitAllowed参数为false,即表示这个Looper不能够被quit掉。其他倒是基本一样。整个android系统中,调用到prepareMainLooper()方法的地方有两个:
/frameworks/base/services/java/com/android/server/HADSystemServer.java94Looper.prepareMainLooper();/frameworks/base/core/java/android/app/HADActivityThread.java5087Looper.prepareMainLooper();
一处在SystemServer——system_server的主线程——的run()方法中,用于为system_server主线程初始化消息处理队列;另外一处在ActivityThread的run()方法中,自然即是创建android app主线程的消息处理队列了。
通过消息与Looper线程交互
那Looper线程的特别之处究竟在哪里呢?如前所述,这种线程有一个Looper与之关联,会使用消息队列,或者称为事件循环来管理执行的流程。那这种特别之处又如何体现呢?答案即是其它线程可以向此类线程中丢消息进来(当然此类线程本身也可以往自己的消息队列里面丢消息),然后在事件处理循环中,这些事件会得到处理。那究竟要如何往Looper线程的消息队列中发送消息呢?
回忆前面我们创建Looper线程的那段代码,不是有创建一个Handler出来嘛。没错,就是通过Handler来向Looper线程的MessageQueue中发送消息的。可以看一下使用Handler向Looper线程发送消息的方法。LooperThread的代码与上面的一样,向Looper线程发送消息的部分的写法:
packagecom.intel.helloworld;importandroid.os.Bundle;importandroid.os.Handler;importandroid.os.Message;importandroid.app.Activity;importandroid.util.Log;importandroid.view.Menu;publicclassMainActivityextendsActivity{publicstaticfinalStringTAG="LifecycleDemoApp";privatestaticfinalStringCompTAG="MainActivity";publicstaticfinalintMESSAGE_WHAT_CREATE=1;publicstaticfinalintMESSAGE_WHAT_START=2;publicstaticfinalintMESSAGE_WHAT_RESUME=3;publicstaticfinalintMESSAGE_WHAT_PAUSE=4;publicstaticfinalintMESSAGE_WHAT_STOP=5;publicstaticfinalintMESSAGE_WHAT_DESTROY=6;LooperThreadmThread;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){Log.d(TAG,CompTAG+":"+"Activity-->onCreate");super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mThread=newLooperThread();mThread.start();}@OverrideprotectedvoidonStart(){Log.d(TAG,CompTAG+":"+"Activity-->onStart");super.onStart();Handlerhandler=mThread.mHandler;Messagemsg=Message.obtain();msg.what=MESSAGE_WHAT_START;handler.sendMessage(msg);}@OverrideprotectedvoidonResume(){Log.d(TAG,CompTAG+":"+"Activity-->onResume");super.onResume();Handlerhandler=mThread.mHandler;Messagemsg=Message.obtain();msg.what=MESSAGE_WHAT_RESUME;handler.sendMessage(msg);}@OverrideprotectedvoidonPause(){Log.d(TAG,CompTAG+":"+"Activity-->onPause");super.onPause();Handlerhandler=mThread.mHandler;Messagemsg=Message.obtain();msg.what=MESSAGE_WHAT_PAUSE;handler.sendMessage(msg);}@OverrideprotectedvoidonStop(){Log.d(TAG,CompTAG+":"+"Activity-->onStop");super.onStop();Handlerhandler=mThread.mHandler;Messagemsg=Message.obtain();msg.what=MESSAGE_WHAT_STOP;handler.sendMessage(msg);}@OverrideprotectedvoidonDestroy(){Log.d(TAG,CompTAG+":"+"Activity-->onDestroy");super.onDestroy();Handlerhandler=mThread.mHandler;Messagemsg=Message.obtain();msg.what=MESSAGE_WHAT_DESTROY;handler.sendMessage(msg);}@OverridepublicbooleanonCreateOptionsMenu(Menumenu){//Inflatethemenu;thisaddsitemstotheactionbarifitispresent.getMenuInflater().inflate(R.menu.main,menu);returntrue;}@OverrideprotectedvoidonSaveInstanceState(BundleoutState){Log.d(TAG,CompTAG+":"+"Activity-->onSaveInstanceState");super.onSaveInstanceState(outState);}}
使用Handler向一个Looper线程发送消息的过程,基本上即是,调用Message.obtain()或Handler.obtainMessage()获取一个Message对象->设置Message对象->调用在Looper线程中创建的Handler对象的方法发送消息。
Handler究竟是如何知道要向哪个MessageQueue发送消息的呢?从前面的代码中,我们似乎看不到任何Handler与MessageQueue能关联起来的迹象。这究竟是怎么回事呢?这也是我们特别强调要使用Looper线程中创建的Handler对象来向该Looper线程中发送消息的原因。我们可以看一下Handler对象构造的过程:
/***Defaultconstructorassociatesthishandlerwiththe{@linkLooper}forthe*currentthread.**Ifthisthreaddoesnothavealooper,thishandlerwon'tbeabletoreceivemessages*soanexceptionisthrown.*/publicHandler(){this(null,false);}/***Constructorassociatesthishandlerwiththe{@linkLooper}forthe*currentthreadandtakesacallbackinterfaceinwhichyoucanhandle*messages.**Ifthisthreaddoesnothavealooper,thishandlerwon'tbeabletoreceivemessages*soanexceptionisthrown.**@paramcallbackThecallbackinterfaceinwhichtohandlemessages,ornull.*/publicHandler(Callbackcallback){this(callback,false);}/***Usetheprovided{@linkLooper}insteadofthedefaultone.**@paramlooperThelooper,mustnotbenull.*/publicHandler(Looperlooper){this(looper,null,false);}/***Usetheprovided{@linkLooper}insteadofthedefaultoneandtakeacallback*interfaceinwhichtohandlemessages.**@paramlooperThelooper,mustnotbenull.*@paramcallbackThecallbackinterfaceinwhichtohandlemessages,ornull.*/publicHandler(Looperlooper,Callbackcallback){this(looper,callback,false);}/***Usethe{@linkLooper}forthecurrentthread*andsetwhetherthehandlershouldbeasynchronous.**Handlersaresynchronousbydefaultunlessthisconstructorisusedtomake*onethatisstrictlyasynchronous.**Asynchronousmessagesrepresentinterruptsoreventsthatdonotrequireglobalordering*withrepresenttosynchronousmessages.Asynchronousmessagesarenotsubjectto*thesynchronizationbarriersintroducedby{@linkMessageQueue#enqueueSyncBarrierlong)}.**@paramasyncIftrue,thehandlercalls{@linkMessage#setAsynchronous(boolean)}for*each{@linkMessage}thatissenttoitor{@linkRunnable}thatispostedtoit.**@hide*/publicHandler(booleanasync){this(null,async);}/***Usethe{@linkLooper}forthecurrentthreadwiththespecifiedcallbackinterface*andsetwhetherthehandlershouldbeasynchronous.**Handlersaresynchronousbydefaultunlessthisconstructorisusedtomake*onethatisstrictlyasynchronous.**Asynchronousmessagesrepresentinterruptsoreventsthatdonotrequireglobalordering*withrepresenttosynchronousmessages.Asynchronousmessagesarenotsubjectto*thesynchronizationbarriersintroducedby{@linkMessageQueue#enqueueSyncBarrierlong)}.**@paramcallbackThecallbackinterfaceinwhichtohandlemessages,ornull.*@paramasyncIftrue,thehandlercalls{@linkMessage#setAsynchronous(boolean)}for*each{@linkMessage}thatissenttoitor{@linkRunnable}thatispostedtoit.**@hide*/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,"ThefollowingHandlerclassshouldbestaticorleaksmightoccur:"+klass.getCanonicalName());}}mLooper=Looper.myLooper();if(mLooper==null){thrownewRuntimeException("Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");}mQueue=mLooper.mQueue;mCallback=callback;mAsynchronous=async;}/***Usetheprovided{@linkLooper}insteadofthedefaultoneandtakeacallback*interfaceinwhichtohandlemessages.Alsosetwhetherthehandler*shouldbeasynchronous.**Handlersaresynchronousbydefaultunlessthisconstructorisusedtomake*onethatisstrictlyasynchronous.**Asynchronousmessagesrepresentinterruptsoreventsthatdonotrequireglobalordering*withrespecttosynchronousmessages.Asynchronousmessagesarenotsubjectto*thesynchronizationbarriersintroducedby{@linkMessageQueue#enqueueSyncBarrier(long)}.**@paramlooperThelooper,mustnotbenull.*@paramcallbackThecallbackinterfaceinwhichtohandlemessages,ornull.*@paramasyncIftrue,thehandlercalls{@linkMessage#setAsynchronous(boolean)}for*each{@linkMessage}thatissenttoitor{@linkRunnable}thatispostedtoit.**@hide*/publicHandler(Looperlooper,Callbackcallback,booleanasync){mLooper=looper;mQueue=looper.mQueue;mCallback=callback;mAsynchronous=async;}
Handler的构造函数共有7个,其中4个不需要传递Looper参数,3个需要。前面我们用的是不需要传递Looper对象的构造函数,因而现在我们主要关注那4个不需要传递Looper参数的。它们都是Handler(Callback callback, boolean async)不同形式的封装,而在这个构造函数中是通过Looper.myLooper()获取到当前线程的Looper对象,并与相关的MessageQueue关联起来的。这也是前面我们在实现Looper线程时,要在其run方法中创建一个public Handler的依据。
当然我们也可以使用那些能够手动传递Looper对象的构造函数,在构造Handler对象时,显式地使其与特定的Looper/消息队列关联起来。比如配合HandlerThread.getLooper()方法来用。
(这个地方我们看到,创建Handler对象时,可以传递另外两个参数,一个是Callback,另一个是async,那这两个参数在这套消息队列机制中,又起到一个什么样的作用呢?后面我们在来解答这个问题。)
Handler提供了两组函数用于向一个Looper线程的MessageQueue中发送消息,分别是postXXX()族和sendXXX()族,这两组函数的调用关系大体如下所示:
我们可以先看一下sendXXX()族消息发送方法:
/***Pushesamessageontotheendofthemessagequeueafterallpendingmessages*beforethecurrenttime.Itwillbereceivedin{@link#handleMessage},*inthethreadattachedtothishandler.**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleansendMessage(Messagemsg){returnsendMessageDelayed(msg,0);}/***SendsaMessagecontainingonlythewhatvalue.**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleansendEmptyMessage(intwhat){returnsendEmptyMessageDelayed(what,0);}/***SendsaMessagecontainingonlythewhatvalue,tobedelivered*afterthespecifiedamountoftimeelapses.*@see#sendMessageDelayed(android.os.Message,long)**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleansendEmptyMessageDelayed(intwhat,longdelayMillis){Messagemsg=Message.obtain();msg.what=what;returnsendMessageDelayed(msg,delayMillis);}/***SendsaMessagecontainingonlythewhatvalue,tobedelivered*ataspecifictime.*@see#sendMessageAtTime(android.os.Message,long)**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleansendEmptyMessageAtTime(intwhat,longuptimeMillis){Messagemsg=Message.obtain();msg.what=what;returnsendMessageAtTime(msg,uptimeMillis);}/***Enqueueamessageintothemessagequeueafterallpendingmessages*before(currenttime+delayMillis).Youwillreceiveitin*{@link#handleMessage},inthethreadattachedtothishandler.**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.Notethata*resultoftruedoesnotmeanthemessagewillbeprocessed--if*thelooperisquitbeforethedeliverytimeofthemessage*occursthenthemessagewillbedropped.*/publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis){if(delayMillis<0){delayMillis=0;}returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);}/***Enqueueamessageintothemessagequeueafterallpendingmessages*beforetheabsolutetime(inmilliseconds)<var>uptimeMillis</var>.*<b>Thetime-baseis{@linkandroid.os.SystemClock#uptimeMillis}.</b>*Youwillreceiveitin{@link#handleMessage},inthethreadattached*tothishandler.**@paramuptimeMillisTheabsolutetimeatwhichthemessageshouldbe*delivered,usingthe*{@linkandroid.os.SystemClock#uptimeMillis}time-base.**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.Notethata*resultoftruedoesnotmeanthemessagewillbeprocessed--if*thelooperisquitbeforethedeliverytimeofthemessage*occursthenthemessagewillbedropped.*/publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){MessageQueuequeue=mQueue;if(queue==null){RuntimeExceptione=newRuntimeException(this+"sendMessageAtTime()calledwithnomQueue");Log.w("Looper",e.getMessage(),e);returnfalse;}returnenqueueMessage(queue,msg,uptimeMillis);}/***Enqueueamessageatthefrontofthemessagequeue,tobeprocessedon*thenextiterationofthemessageloop.Youwillreceiveitin*{@link#handleMessage},inthethreadattachedtothishandler.*<b>Thismethodisonlyforuseinveryspecialcircumstances--it*caneasilystarvethemessagequeue,causeorderingproblems,orhave*otherunexpectedside-effects.</b>**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleansendMessageAtFrontOfQueue(Messagemsg){MessageQueuequeue=mQueue;if(queue==null){RuntimeExceptione=newRuntimeException(this+"sendMessageAtTime()calledwithnomQueue");Log.w("Looper",e.getMessage(),e);returnfalse;}returnenqueueMessage(queue,msg,0);}privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){msg.target=this;if(mAsynchronous){msg.setAsynchronous(true);}returnqueue.enqueueMessage(msg,uptimeMillis);}
这些方法之间大多只有一些细微的差别,它们最终都调用Handler.enqueueMessage()/MessageQueue.enqueueMessage()方法。(哈哈,这个地方,被我们逮到一个Handler类某贡献者所犯的copy-paste错误:仔细看一下sendMessageAtTime()和sendMessageAtFrontOfQueue()这两个方法,创建RuntimeException的部分,消息中都是"sendMessageAtTime()"。)Handler实际的职责,并不完全如它的名称所示,在处理message外,它还要负责发送Message到MessageQueue。
注意,在Handler.enqueueMessage()中,会将Message的target设为this,而且是不加检查,强制覆盖原来的值。后面我们将会看到,Message的target就是Message被dispatched到的Handler,也是将会处理这条Message的Handler。这个地方强制覆盖的逻辑表明,我们用哪个Handler来发送一条消息,那么这条消息就将会被dispatched给哪个Handler来处理,消息的发送者即接收者。这使得Handler那些obtainMessage()方法,及Message需要Handler参数的那些obtain()方法显得非常多余。通过这些方法会在获取Message时设置它的target,但这些设置又总是会在后面被无条件地覆盖掉。
再来看一下MessageQueue.enqueueMessage()方法:
booleanenqueueMessage(Messagemsg,longwhen){if(msg.isInUse()){thrownewAndroidRuntimeException(msg+"Thismessageisalreadyinuse.");}if(msg.target==null){thrownewAndroidRuntimeException("Messagemusthaveatarget.");}booleanneedWake;synchronized(this){if(mQuiting){RuntimeExceptione=newRuntimeException(msg.target+"sendingmessagetoaHandleronadeadthread");Log.w("MessageQueue",e.getMessage(),e);returnfalse;}msg.when=when;Messagep=mMessages;if(p==null||when==0||when<p.when){//Newhead,wakeuptheeventqueueifblocked.msg.next=p;mMessages=msg;needWake=mBlocked;}else{//Insertedwithinthemiddleofthequeue.Usuallywedon'thavetowake//uptheeventqueueunlessthereisabarrierattheheadofthequeue//andthemessageistheearliestasynchronousmessageinthequeue.needWake=mBlocked&&p.target==null&&msg.isAsynchronous();Messageprev;for(;;){prev=p;p=p.next;if(p==null||when<p.when){break;}if(needWake&&p.isAsynchronous()){needWake=false;}}msg.next=p;//invariant:p==prev.nextprev.next=msg;}}if(needWake){nativeWake(mPtr);}returntrue;}
此处我们看到,MessageQueue用一个单向链表来保存所有的Messages,在链表中各个Message按照其请求执行的时间先后来排序。将Message插入MessageQueue的算法也还算清晰简洁,不必赘述。但此处,MessageQueue/Message的author为什么要自己实现一个单向链表,而没有用Java标准库提供的容器组件呢?是为了插入一条新的Message方便,还是仅仅为了练习怎么用Java实现单向链表?wake的逻辑后面我们会再来研究。
向MessageQueue中发送消息的postXXX()方法:
/***CausestheRunnablertobeaddedtothemessagequeue.*Therunnablewillberunonthethreadtowhichthishandleris*attached.**@paramrTheRunnablethatwillbeexecuted.**@returnReturnstrueiftheRunnablewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleanpost(Runnabler){returnsendMessageDelayed(getPostMessage(r),0);}/***CausestheRunnablertobeaddedtothemessagequeue,toberun*ataspecifictimegivenby<var>uptimeMillis</var>.*<b>Thetime-baseis{@linkandroid.os.SystemClock#uptimeMillis}.</b>*Timespentindeepsleepwilladdanadditionaldelaytoexecution.*Therunnablewillberunonthethreadtowhichthishandlerisattached.**@paramrTheRunnablethatwillbeexecuted.*@paramuptimeMillisTheabsolutetimeatwhichthecallbackshouldrun,*usingthe{@linkandroid.os.SystemClock#uptimeMillis}time-base.**@returnReturnstrueiftheRunnablewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.Notethata*resultoftruedoesnotmeantheRunnablewillbeprocessed--if*thelooperisquitbeforethedeliverytimeofthemessage*occursthenthemessagewillbedropped.*/publicfinalbooleanpostAtTime(Runnabler,longuptimeMillis){returnsendMessageAtTime(getPostMessage(r),uptimeMillis);}/***CausestheRunnablertobeaddedtothemessagequeue,toberun*ataspecifictimegivenby<var>uptimeMillis</var>.*<b>Thetime-baseis{@linkandroid.os.SystemClock#uptimeMillis}.</b>*Timespentindeepsleepwilladdanadditionaldelaytoexecution.*Therunnablewillberunonthethreadtowhichthishandlerisattached.**@paramrTheRunnablethatwillbeexecuted.*@paramuptimeMillisTheabsolutetimeatwhichthecallbackshouldrun,*usingthe{@linkandroid.os.SystemClock#uptimeMillis}time-base.**@returnReturnstrueiftheRunnablewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.Notethata*resultoftruedoesnotmeantheRunnablewillbeprocessed--if*thelooperisquitbeforethedeliverytimeofthemessage*occursthenthemessagewillbedropped.**@seeandroid.os.SystemClock#uptimeMillis*/publicfinalbooleanpostAtTime(Runnabler,Objecttoken,longuptimeMillis){returnsendMessageAtTime(getPostMessage(r,token),uptimeMillis);}/***CausestheRunnablertobeaddedtothemessagequeue,toberun*afterthespecifiedamountoftimeelapses.*Therunnablewillberunonthethreadtowhichthishandler*isattached.*<b>Thetime-baseis{@linkandroid.os.SystemClock#uptimeMillis}.</b>*Timespentindeepsleepwilladdanadditionaldelaytoexecution.**@paramrTheRunnablethatwillbeexecuted.*@paramdelayMillisThedelay(inmilliseconds)untiltheRunnable*willbeexecuted.**@returnReturnstrueiftheRunnablewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.Notethata*resultoftruedoesnotmeantheRunnablewillbeprocessed--*ifthelooperisquitbeforethedeliverytimeofthemessage*occursthenthemessagewillbedropped.*/publicfinalbooleanpostDelayed(Runnabler,longdelayMillis){returnsendMessageDelayed(getPostMessage(r),delayMillis);}/***PostsamessagetoanobjectthatimplementsRunnable.*CausestheRunnablertoexecutedonthenextiterationthroughthe*messagequeue.Therunnablewillberunonthethreadtowhichthis*handlerisattached.*<b>Thismethodisonlyforuseinveryspecialcircumstances--it*caneasilystarvethemessagequeue,causeorderingproblems,orhave*otherunexpectedside-effects.</b>**@paramrTheRunnablethatwillbeexecuted.**@returnReturnstrueifthemessagewassuccessfullyplacedintothe*messagequeue.Returnsfalseonfailure,usuallybecausethe*looperprocessingthemessagequeueisexiting.*/publicfinalbooleanpostAtFrontOfQueue(Runnabler){returnsendMessageAtFrontOfQueue(getPostMessage(r));}privatestaticMessagegetPostMessage(Runnabler){Messagem=Message.obtain();m.callback=r;returnm;}privatestaticMessagegetPostMessage(Runnabler,Objecttoken){Messagem=Message.obtain();m.obj=token;m.callback=r;returnm;}
这组方法相对于前面的sendXXX()族方法而言,其特殊之处在于,它们都需要传入一个Runnable参数,post的消息,其特殊之处也正在于,Message的callback将是传入的Runnable对象。这些特别的地方将影响这些消息在dispatch时的行为。
消息队列中消息的处理
消息队列中的消息是在Looper.loop()中被取出处理的:
/***Runthemessagequeueinthisthread.Besuretocall*{@link#quit()}toendtheloop.*/publicstaticvoidloop(){finalLooperme=myLooper();if(me==null){thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");}finalMessageQueuequeue=me.mQueue;//Makesuretheidentityofthisthreadisthatofthelocalprocess,//andkeeptrackofwhatthatidentitytokenactuallyis.Binder.clearCallingIdentity();finallongident=Binder.clearCallingIdentity();for(;;){Messagemsg=queue.next();//mightblockif(msg==null){//Nomessageindicatesthatthemessagequeueisquitting.return;}//Thismustbeinalocalvariable,incaseaUIeventsetstheloggerPrinterlogging=me.mLogging;if(logging!=null){logging.println(">>>>>Dispatchingto"+msg.target+""+msg.callback+":"+msg.what);}msg.target.dispatchMessage(msg);if(logging!=null){logging.println("<<<<<Finishedto"+msg.target+""+msg.callback);}//Makesurethatduringthecourseofdispatchingthe//identityofthethreadwasn'tcorrupted.finallongnewIdent=Binder.clearCallingIdentity();if(ident!=newIdent){Log.wtf(TAG,"Threadidentitychangedfrom0x"+Long.toHexString(ident)+"to0x"+Long.toHexString(newIdent)+"whiledispatchingto"+msg.target.getClass().getName()+""+msg.callback+"what="+msg.what);}msg.recycle();}}
在取出的msg为NULL之前,消息处理循环都一直运行。为NULL的msg表明消息队列被停掉了。在这个循环中,被取出的消息会被dispatch给一个Handler处理,即是msg.target,执行Handler.dispatchMessage()方法。
注意:Looper.loop()循环体的末尾,调用了从消息队列中取出且已经被dispatched处理的Message的recycle()方法,这表明Looper会帮我们自动回收发送到它的消息队列的消息。在我们将一条消息发送给Looper线程的消息队列之后,我们就不需要再担心消息的回收问题了,Looper自会帮我们很好的处理
接着来看Handler.dispatchMessage():
/***CallbackinterfaceyoucanusewheninstantiatingaHandlertoavoid*havingtoimplementyourownsubclassofHandler.**@parammsgA{@linkandroid.os.MessageMessage}object*@returnTrueifnofurtherhandlingisdesired*/publicinterfaceCallback{publicbooleanhandleMessage(Messagemsg);}/***Subclassesmustimplementthistoreceivemessages.*/publicvoidhandleMessage(Messagemsg){}/***Handlesystemmessageshere.*/publicvoiddispatchMessage(Messagemsg){if(msg.callback!=null){handleCallback(msg);}else{if(mCallback!=null){if(mCallback.handleMessage(msg)){return;}}handleMessage(msg);}}privatestaticvoidhandleCallback(Messagemessage){message.callback.run();}
可以认为有三种对象可能会实际处理一条消息,分别是消息的Runnable callback,Handler的Callback mCallback和Handler对象本身。但这三种对象在获取消息的处理权方面有一定的优先级,消息的Runnable callback优先级最高,在它不为空时,只执行这个callback;优先级次高的是Handler的Callback mCallback,在它不为空时,Handler会先把消息丢给它处理,如果它不处理返回了false,Handler才会调用自己的handleMessage()来处理。
通常,Handler的handleMessage()方法通常需要override,来实现消息处理的主要逻辑。Handler的mCallback,使得开发者可以比较方便的将消息处理的逻辑和发送消息的Handler完全分开。
此处也可见post消息的特殊之处,此类消息将完全绕过Handler中用于处理消息的handleMessage() 方法,而只会执行消息的sender所实现的Runnable。
Sleep-Wakeup机制
还有一个问题,当MessageQueue中没有Messages时,Looper线程会做什么呢?它会不停地轮询,并检查消息队列中是否有消息吗?计算机科学发展到现在,闭上眼睛我们都能猜到,Looper线程一定不会去轮询的。Looper线程也确实没有去轮询消息队列。在消息队列为空时,Looper线程会去休眠,然后在消息队列中有了消息之后,再被唤醒。但这样的机制又是如何实现的呢?
Sleep-Wakeup机制所需设施的建立
我们从Sleep-Wakeup机制所需设施的建立开始。回忆前面的Looper构造函数,它会创建一个MessageQueue对象,而Sleep-Wakeup机制所需设施正是在MessageQueue对象的创建过程中创建出来的。(在android消息队列机制中,消息取出和压入的主要逻辑都在MessageQueue中完成,MessageQueue实现一个定制的阻塞队列,将等待-唤醒的逻辑都放在这个类里想必也没什么让人吃惊的地方吧。)我们来看MessageQueue的构造函数:
MessageQueue(booleanquitAllowed){mQuitAllowed=quitAllowed;mPtr=nativeInit();}privatenativestaticlongnativeInit();
这个方法调用nativeInit()方法来创建Sleep-Wakeup机制所需设施。来看nativeInit()的实现(在frameworks/base/core/jni/android_os_MessageQueue.cpp):
NativeMessageQueue::NativeMessageQueue():mInCallback(false),mExceptionObj(NULL){mLooper=Looper::getForThread();if(mLooper==NULL){mLooper=newLooper(false);Looper::setForThread(mLooper);}}staticjintandroid_os_MessageQueue_nativeInit(JNIEnv*env,jclassclazz){NativeMessageQueue*nativeMessageQueue=newNativeMessageQueue();if(!nativeMessageQueue){jniThrowRuntimeException(env,"Unabletoallocatenativequeue");return0;}nativeMessageQueue->incStrong(env);returnreinterpret_cast<jint>(nativeMessageQueue);}staticJNINativeMethodgMessageQueueMethods[]={/*name,signature,funcPtr*/{"nativeInit","()I",(void*)android_os_MessageQueue_nativeInit},{"nativeDestroy","(I)V",(void*)android_os_MessageQueue_nativeDestroy},{"nativePollOnce","(II)V",(void*)android_os_MessageQueue_nativePollOnce},{"nativeWake","(I)V",(void*)android_os_MessageQueue_nativeWake}};
可以看到,nativeInit()所做的事情,就是创建一个NativeMessageQueue对象,在NativeMessageQueue的构造函数中,会来创建一个Looper对象。与Java层的Looper对象类似,native层的这种Looper对象也是保存在线程局部存储变量中的,每个线程一个。接着我们来看Looper类的构造函数和Looper::getForThread()函数,来了解一下,native层的线程局部存储API的用法(Looper类的实现在frameworks/native/libs/utils/Looper.cpp):
//Hintfornumberoffiledescriptorstobeassociatedwiththeepollinstance.staticconstintEPOLL_SIZE_HINT=8;//Maximumnumberoffiledescriptorsforwhichtoretrievepolleventseachiteration.staticconstintEPOLL_MAX_EVENTS=16;staticpthread_once_tgTLSOnce=PTHREAD_ONCE_INIT;staticpthread_key_tgTLSKey=0;Looper::Looper(boolallowNonCallbacks):mAllowNonCallbacks(allowNonCallbacks),mSendingMessage(false),mResponseIndex(0),mNextMessageUptime(LLONG_MAX){intwakeFds[2];intresult=pipe(wakeFds);LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotcreatewakepipe.errno=%d",errno);mWakeReadPipeFd=wakeFds[0];mWakeWritePipeFd=wakeFds[1];result=fcntl(mWakeReadPipeFd,F_SETFL,O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotmakewakereadpipenon-blocking.errno=%d",errno);result=fcntl(mWakeWritePipeFd,F_SETFL,O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotmakewakewritepipenon-blocking.errno=%d",errno);//Allocatetheepollinstanceandregisterthewakepipe.mEpollFd=epoll_create(EPOLL_SIZE_HINT);LOG_ALWAYS_FATAL_IF(mEpollFd<0,"Couldnotcreateepollinstance.errno=%d",errno);structepoll_eventeventItem;memset(&eventItem,0,sizeof(epoll_event));//zerooutunusedmembersofdatafieldunioneventItem.events=EPOLLIN;eventItem.data.fd=mWakeReadPipeFd;result=epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeReadPipeFd,&eventItem);LOG_ALWAYS_FATAL_IF(result!=0,"Couldnotaddwakereadpipetoepollinstance.errno=%d",errno);}voidLooper::initTLSKey(){intresult=pthread_key_create(&gTLSKey,threadDestructor);LOG_ALWAYS_FATAL_IF(result!=0,"CouldnotallocateTLSkey.");}voidLooper::threadDestructor(void*st){Looper*constself=static_cast<Looper*>(st);if(self!=NULL){self->decStrong((void*)threadDestructor);}}voidLooper::setForThread(constsp<Looper>&looper){sp<Looper>old=getForThread();//alsohasside-effectofinitializingTLSif(looper!=NULL){looper->incStrong((void*)threadDestructor);}pthread_setspecific(gTLSKey,looper.get());if(old!=NULL){old->decStrong((void*)threadDestructor);}}sp<Looper>Looper::getForThread(){intresult=pthread_once(&gTLSOnce,initTLSKey);LOG_ALWAYS_FATAL_IF(result!=0,"pthread_oncefailed");return(Looper*)pthread_getspecific(gTLSKey);}
关于pthread库提供的线程局部存储API的用法,可以看到,每个线程局部存储对象,都需要一个key,通过pthread_key_create()函数创建,随后各个线程就可以通过这个key并借助于pthread_setspecific()和pthread_getspecific()函数来保存或者获取相应的线程局部存储的变量了。再来看Looper的构造函数。它创建了一个pipe,两个文件描述符。然后设置管道的两个文件描述属性为非阻塞I/O。接着是创建并设置epoll实例。由此我们了解到,android的消息队列是通过epoll机制来实现其Sleep-Wakeup机制的。
唤醒
然后来看当其他线程向Looper线程的MessageQueue中插入了消息时,Looper线程是如何被叫醒的。回忆我们前面看到的MessageQueue类的enqueueMessage()方法,它在最后插入消息之后,有调用一个nativeWake()方法。没错,正是这个nativeWake()方法执行了叫醒Looper线程的动作。那它又是如何叫醒Looper线程的呢?来看它的实现:
staticvoidandroid_os_MessageQueue_nativeWake(JNIEnv*env,jclassclazz,jintptr){NativeMessageQueue*nativeMessageQueue=reinterpret_cast<NativeMessageQueue*>(ptr);returnnativeMessageQueue->wake();}//----------------------------------------------------------------------------staticJNINativeMethodgMessageQueueMethods[]={/*name,signature,funcPtr*/{"nativeInit","()I",(void*)android_os_MessageQueue_nativeInit},{"nativeDestroy","(I)V",(void*)android_os_MessageQueue_nativeDestroy},{"nativePollOnce","(II)V",(void*)android_os_MessageQueue_nativePollOnce},{"nativeWake","(I)V",(void*)android_os_MessageQueue_nativeWake}};
它只是调用了native层的Looper对象的wake()函数。接着再来看native Looper的wake()函数:
voidLooper::wake(){#ifDEBUG_POLL_AND_WAKEALOGD("%p~wake",this);#endifssize_tnWrite;do{nWrite=write(mWakeWritePipeFd,"W",1);}while(nWrite==-1&&errno==EINTR);if(nWrite!=1){if(errno!=EAGAIN){ALOGW("Couldnotwritewakesignal,errno=%d",errno);}}}
它所做的事情,就是向管道的用于写的那个文件中写入一个“W”字符。
休眠
Looper线程休眠的过程。我们知道,Looper线程在Looper.loop()方法中,不断地从MessageQueue中取出消息,然后处理,如此循环往复,永不止息。不难想象,休眠的时机应该是在取出消息的时候。Looper.loop()通过MessageQueue.next()从消息队列中取出消息。来看MessageQueue.next()方法:
Messagenext(){intpendingIdleHandlerCount=-1;//-1onlyduringfirstiterationintnextPollTimeoutMillis=0;for(;;){if(nextPollTimeoutMillis!=0){Binder.flushPendingCommands();}nativePollOnce(mPtr,nextPollTimeoutMillis);synchronized(this){//Trytoretrievethenextmessage.Returniffound.finallongnow=SystemClock.uptimeMillis();MessageprevMsg=null;Messagemsg=mMessages;if(msg!=null&&msg.target==null){//Stalledbyabarrier.Findthenextasynchronousmessageinthequeue.do{prevMsg=msg;msg=msg.next;}while(msg!=null&&!msg.isAsynchronous());}if(msg!=null){if(now<msg.when){//Nextmessageisnotready.Setatimeouttowakeupwhenitisready.nextPollTimeoutMillis=(int)Math.min(msg.when-now,Integer.MAX_VALUE);}else{//Gotamessage.mBlocked=false;if(prevMsg!=null){prevMsg.next=msg.next;}else{mMessages=msg.next;}msg.next=null;if(false)Log.v("MessageQueue","Returningmessage:"+msg);msg.markInUse();returnmsg;}}else{//Nomoremessages.nextPollTimeoutMillis=-1;}//Processthequitmessagenowthatallpendingmessageshavebeenhandled.if(mQuiting){dispose();returnnull;}//Iffirsttimeidle,thengetthenumberofidlerstorun.//Idlehandlesonlyrunifthequeueisemptyorifthefirstmessage//inthequeue(possiblyabarrier)isduetobehandledinthefuture.if(pendingIdleHandlerCount<0&&(mMessages==null||now<mMessages.when)){pendingIdleHandlerCount=mIdleHandlers.size();}if(pendingIdleHandlerCount<=0){//Noidlehandlerstorun.Loopandwaitsomemore.mBlocked=true;continue;}if(mPendingIdleHandlers==null){mPendingIdleHandlers=newIdleHandler[Math.max(pendingIdleHandlerCount,4)];}mPendingIdleHandlers=mIdleHandlers.toArray(mPendingIdleHandlers);}//Runtheidlehandlers.//Weonlyeverreachthiscodeblockduringthefirstiteration.for(inti=0;i<pendingIdleHandlerCount;i++){finalIdleHandleridler=mPendingIdleHandlers[i];mPendingIdleHandlers[i]=null;//releasethereferencetothehandlerbooleankeep=false;try{keep=idler.queueIdle();}catch(Throwablet){Log.wtf("MessageQueue","IdleHandlerthrewexception",t);}if(!keep){synchronized(this){mIdleHandlers.remove(idler);}}}//Resettheidlehandlercountto0sowedonotrunthemagain.pendingIdleHandlerCount=0;//Whilecallinganidlehandler,anewmessagecouldhavebeendelivered//sogobackandlookagainforapendingmessagewithoutwaiting.nextPollTimeoutMillis=0;}}
值得注意的是上面那个对于nativePollOnce()的调用。wait机制的实现正在于此。来看这个方法的实现,在native的JNI code里面:
classMessageQueue:publicRefBase{public:/*Getsthemessagequeue'slooper.*/inlinesp<Looper>getLooper()const{returnmLooper;}/*CheckswhethertheJNIenvironmenthasapendingexception.**Ifanexceptionoccurred,logsittogetherwiththespecifiedmessage,*andcallsraiseException()toensuretheexceptionwillberaisedwhen*thecallbackreturns,clearsthependingexceptionfromtheenvironment,*thenreturnstrue.**Ifnoexceptionoccurred,returnsfalse.*/boolraiseAndClearException(JNIEnv*env,constchar*msg);/*Raisesanexceptionfromwithinacallbackfunction.*Theexceptionwillberethrownwhencontrolreturnstothemessagequeuewhich*willtypicallycausetheapplicationtocrash.**Thismessagecanonlybecalledfromwithinacallbackfunction.Ifitiscalled*atanyothertime,theprocesswillsimplybekilled.**DoesnothingifexceptionisNULL.**(Thismethoddoesnottakeownershipoftheexceptionobjectreference.*Thecallerisresponsibleforreleasingitsreferencewhenitisdone.)*/virtualvoidraiseException(JNIEnv*env,constchar*msg,jthrowableexceptionObj)=0;protected:MessageQueue();virtual~MessageQueue();protected:sp<Looper>mLooper;};classNativeMessageQueue:publicMessageQueue{public:NativeMessageQueue();virtual~NativeMessageQueue();virtualvoidraiseException(JNIEnv*env,constchar*msg,jthrowableexceptionObj);voidpollOnce(JNIEnv*env,inttimeoutMillis);voidwake();private:boolmInCallback;jthrowablemExceptionObj;};voidNativeMessageQueue::pollOnce(JNIEnv*env,inttimeoutMillis){mInCallback=true;mLooper->pollOnce(timeoutMillis);mInCallback=false;if(mExceptionObj){env->Throw(mExceptionObj);env->DeleteLocalRef(mExceptionObj);mExceptionObj=NULL;}}staticvoidandroid_os_MessageQueue_nativePollOnce(JNIEnv*env,jclassclazz,jintptr,jinttimeoutMillis){NativeMessageQueue*nativeMessageQueue=reinterpret_cast<NativeMessageQueue*>(ptr);nativeMessageQueue->pollOnce(env,timeoutMillis);}
继续追Looper::pollOnce()的实现(在frameworks/native/libs/utils/Looper.cpp):
intLooper::pollOnce(inttimeoutMillis,int*outFd,int*outEvents,void**outData){intresult=0;for(;;){while(mResponseIndex<mResponses.size()){constResponse&response=mResponses.itemAt(mResponseIndex++);intident=response.request.ident;if(ident>=0){intfd=response.request.fd;intevents=response.events;void*data=response.request.data;#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-returningsignalledidentifier%d:""fd=%d,events=0x%x,data=%p",this,ident,fd,events,data);#endifif(outFd!=NULL)*outFd=fd;if(outEvents!=NULL)*outEvents=events;if(outData!=NULL)*outData=data;returnident;}}if(result!=0){#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-returningresult%d",this,result);#endifif(outFd!=NULL)*outFd=0;if(outEvents!=NULL)*outEvents=0;if(outData!=NULL)*outData=NULL;returnresult;}result=pollInner(timeoutMillis);}}intLooper::pollInner(inttimeoutMillis){#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-waiting:timeoutMillis=%d",this,timeoutMillis);#endif//Adjustthetimeoutbasedonwhenthenextmessageisdue.if(timeoutMillis!=0&&mNextMessageUptime!=LLONG_MAX){nsecs_tnow=systemTime(SYSTEM_TIME_MONOTONIC);intmessageTimeoutMillis=toMillisecondTimeoutDelay(now,mNextMessageUptime);if(messageTimeoutMillis>=0&&(timeoutMillis<0||messageTimeoutMillis<timeoutMillis)){timeoutMillis=messageTimeoutMillis;}#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-nextmessagein%lldns,adjustedtimeout:timeoutMillis=%d",this,mNextMessageUptime-now,timeoutMillis);#endif}//Poll.intresult=ALOOPER_POLL_WAKE;mResponses.clear();mResponseIndex=0;structepoll_eventeventItems[EPOLL_MAX_EVENTS];inteventCount=epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis);//Acquirelock.mLock.lock();//Checkforpollerror.if(eventCount<0){if(errno==EINTR){gotoDone;}ALOGW("Pollfailedwithanunexpectederror,errno=%d",errno);result=ALOOPER_POLL_ERROR;gotoDone;}//Checkforpolltimeout.if(eventCount==0){#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-timeout",this);#endifresult=ALOOPER_POLL_TIMEOUT;gotoDone;}//Handleallevents.#ifDEBUG_POLL_AND_WAKEALOGD("%p~pollOnce-handlingeventsfrom%dfds",this,eventCount);#endiffor(inti=0;i<eventCount;i++){intfd=eventItems[i].data.fd;uint32_tepollEvents=eventItems[i].events;if(fd==mWakeReadPipeFd){if(epollEvents&EPOLLIN){awoken();}else{ALOGW("Ignoringunexpectedepollevents0x%xonwakereadpipe.",epollEvents);}}else{ssize_trequestIndex=mRequests.indexOfKey(fd);if(requestIndex>=0){intevents=0;if(epollEvents&EPOLLIN)events|=ALOOPER_EVENT_INPUT;if(epollEvents&EPOLLOUT)events|=ALOOPER_EVENT_OUTPUT;if(epollEvents&EPOLLERR)events|=ALOOPER_EVENT_ERROR;if(epollEvents&EPOLLHUP)events|=ALOOPER_EVENT_HANGUP;pushResponse(events,mRequests.valueAt(requestIndex));}else{ALOGW("Ignoringunexpectedepollevents0x%xonfd%dthatis""nolongerregistered.",epollEvents,fd);}}}Done:;//Invokependingmessagecallbacks.mNextMessageUptime=LLONG_MAX;while(mMessageEnvelopes.size()!=0){nsecs_tnow=systemTime(SYSTEM_TIME_MONOTONIC);constMessageEnvelope&messageEnvelope=mMessageEnvelopes.itemAt(0);if(messageEnvelope.uptime<=now){//Removetheenvelopefromthelist.//WekeepastrongreferencetothehandleruntilthecalltohandleMessage//finishes.Thenwedropitsothatthehandlercanbedeleted*before*//wereacquireourlock.{//obtainhandlersp<MessageHandler>handler=messageEnvelope.handler;Messagemessage=messageEnvelope.message;mMessageEnvelopes.removeAt(0);mSendingMessage=true;mLock.unlock();#ifDEBUG_POLL_AND_WAKE||DEBUG_CALLBACKSALOGD("%p~pollOnce-sendingmessage:handler=%p,what=%d",this,handler.get(),message.what);#endifhandler->handleMessage(message);}//releasehandlermLock.lock();mSendingMessage=false;result=ALOOPER_POLL_CALLBACK;}else{//Thelastmessageleftattheheadofthequeuedeterminesthenextwakeuptime.mNextMessageUptime=messageEnvelope.uptime;break;}}//Releaselock.mLock.unlock();//Invokeallresponsecallbacks.for(size_ti=0;i<mResponses.size();i++){Response&response=mResponses.editItemAt(i);if(response.request.ident==ALOOPER_POLL_CALLBACK){intfd=response.request.fd;intevents=response.events;void*data=response.request.data;#ifDEBUG_POLL_AND_WAKE||DEBUG_CALLBACKSALOGD("%p~pollOnce-invokingfdeventcallback%p:fd=%d,events=0x%x,data=%p",this,response.request.callback.get(),fd,events,data);#endifintcallbackResult=response.request.callback->handleEvent(fd,events,data);if(callbackResult==0){removeFd(fd);}//Clearthecallbackreferenceintheresponsestructurepromptlybecausewe//willnotcleartheresponsevectoritselfuntilthenextpoll.response.request.callback.clear();result=ALOOPER_POLL_CALLBACK;}}returnresult;}
它通过调用epoll_wait()函数来等待消息的到来。
HandlerThread的退出
HandlerThread或使用Looper/MessageQueue自定义的类似东西,必须在不需要时被停掉。如前所见,每次创建MessageQueue,都会占用好几个描述符,但在Linux/Android上,一个进程所能打开的文件描述符的最大个数是有限制的,大多为1024个。如果一个app打开的文件描述符达到了这个上限,则将会出现许多各式各样的古怪问题,像进程间通信,socket,输入系统等很多机制,都会依赖于类文件的东西。同时,HandlerThread也总会占用一个线程。这些资源都是只有在显式地停掉之后才会被释放的。
我们来看一下HandlerThread的退出机制。先来看一个使用了HandlerThread,并适时地退出的例子,代码在frameworks/base/core/java/android/app/IntentService.java:
@OverridepublicvoidonCreate(){//TODO:Itwouldbenicetohaveanoptiontoholdapartialwakelock//duringprocessing,andtohaveastaticstartService(Context,Intent)//methodthatwouldlaunchtheservice&handoffawakelock.super.onCreate();HandlerThreadthread=newHandlerThread("IntentService["+mName+"]");thread.start();mServiceLooper=thread.getLooper();mServiceHandler=newServiceHandler(mServiceLooper);}@OverridepublicvoidonStart(Intentintent,intstartId){Messagemsg=mServiceHandler.obtainMessage();msg.arg1=startId;msg.obj=intent;mServiceHandler.sendMessage(msg);}/***YoushouldnotoverridethismethodforyourIntentService.Instead,*override{@link#onHandleIntent},whichthesystemcallswhentheIntentService*receivesastartrequest.*@seeandroid.app.Service#onStartCommand*/@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){onStart(intent,startId);returnmRedelivery?START_REDELIVER_INTENT:START_NOT_STICKY;}@OverridepublicvoidonDestroy(){mServiceLooper.quit();}
在这个例子中,Service的onCreate()方法创建了HandlerThread,保存了HandlerThread的Looper,然后在Service的onDestroy()方法中停掉了Looper,实际上也即是退出了HandlerThread。
来看一下Looper停止方法具体的实现:
/***Quitsthelooper.*<p>*Causesthe{@link#loop}methodtoterminatewithoutprocessingany*moremessagesinthemessagequeue.*</p><p>*Anyattempttopostmessagestothequeueafterthelooperisaskedtoquitwillfail.*Forexample,the{@linkHandler#sendMessage(Message)}methodwillreturnfalse.*</p><pclass="note">*Usingthismethodmaybeunsafebecausesomemessagesmaynotbedelivered*beforethelooperterminates.Considerusing{@link#quitSafely}insteadtoensure*thatallpendingworkiscompletedinanorderlymanner.*</p>**@see#quitSafely*/publicvoidquit(){mQueue.quit(false);}/***Quitstheloopersafely.*<p>*Causesthe{@link#loop}methodtoterminateassoonasallremainingmessages*inthemessagequeuethatarealreadyduetobedeliveredhavebeenhandled.*Howeverpendingdelayedmessageswithduetimesinthefuturewillnotbe*deliveredbeforetheloopterminates.*</p><p>*Anyattempttopostmessagestothequeueafterthelooperisaskedtoquitwillfail.*Forexample,the{@linkHandler#sendMessage(Message)}methodwillreturnfalse.*</p>*/publicvoidquitSafely(){mQueue.quit(true);}
Looper有提供两个退出方法,quit()和quitSafely(),这两个方法都会阻止再向消息队列中发送消息。但它们的主要区别在于,前者不会再处理消息队列中还没有被处理的所有消息,而后者则会在处理完那些已经到期的消息之后才真的退出。
由前面我们对Looper.loop()方法的分析,也不难理解,MessageQueue退出即Looper退出。此处也是直接调用了MessageQueue.quit()方法。那我们就来看一下MessageQueue的quit()方法:
voidquit(booleansafe){if(!mQuitAllowed){thrownewRuntimeException("Mainthreadnotallowedtoquit.");}synchronized(this){if(mQuitting){return;}mQuitting=true;if(safe){removeAllFutureMessagesLocked();}else{removeAllMessagesLocked();}//WecanassumemPtr!=0becausemQuittingwaspreviouslyfalse.nativeWake(mPtr);}}
主要做了几个事情:第一,设置标记mQuitting为true,以表明HandlerThread要退出了;第二,根据传入的参数safe,删除队列里面适当类型的消息;第三,调用nativeWake(mPtr),将HandlerThread线程唤醒。我们都知道,Java里面是没有办法直接终止另外一个线程的,同时强制中止一个线程也是很不安全的,所以,这里也是只设置一个标记,然后在MessageQueue.next()中获取消息时检查此标记,以在适当的时候退出。MessageQueue.next()里中止消息处理循环的,主要是下面这几行:
//Processthequitmessagenowthatallpendingmessageshavebeenhandled.if(mQuitting){dispose();returnnull;}
然后在 MessageQueue.dispose()方法中完成最终的退出,及资源清理的工作:
privatevoiddispose(){if(mPtr!=0){nativeDestroy(mPtr);mPtr=0;}}
android中消息队列机制,大体如此。
Done。
更多相关文章
- Android调试工具及方法
- 深入分析Android中Dialog
- 一套完善的Android异步任务类
- Android(安卓)蓝牙开发基本流程
- [Android] 修图工具Draw9patch使用小结(附ubuntu快捷截图方法)
- Google Android(安卓)JNI使用方法
- Android(安卓)UI布局
- Android理解:显式和隐式Intent
- Android中的Surface和SurfaceView