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());获取HandlerThreadLooper的方法(这个方法对于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中发送消息的。可以看一下使用HandlerLooper线程发送消息的方法。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发送消息的呢?从前面的代码中,我们似乎看不到任何HandlerMessageQueue能关联起来的迹象。这究竟是怎么回事呢?这也是我们特别强调要使用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()中,会Messagetarget设为this,而且是不加检查,强制覆盖原来的值。后面我们将会看到,Messagetarget就是Message被dispatched到的Handler,也是将会处理这条MessageHandler。这个地方强制覆盖的逻辑表明,我们用哪个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处理的Messagerecycle()方法,这表明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();}

在这个例子中,ServiceonCreate()方法创建了HandlerThread,保存了HandlerThreadLooper,然后在ServiceonDestroy()方法中停掉了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);}}

主要做了几个事情:第一,设置标记mQuittingtrue,以表明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。

更多相关文章

  1. Android调试工具及方法
  2. 深入分析Android中Dialog
  3. 一套完善的Android异步任务类
  4. Android(安卓)蓝牙开发基本流程
  5. [Android] 修图工具Draw9patch使用小结(附ubuntu快捷截图方法)
  6. Google Android(安卓)JNI使用方法
  7. Android(安卓)UI布局
  8. Android理解:显式和隐式Intent
  9. Android中的Surface和SurfaceView

随机推荐

  1. Android(安卓)EditText涓嶅脊鍑鸿緭鍏ユ
  2. Android我还可以相信你多少系列文章一之
  3. Android(安卓)一个应用的执行过程
  4. Android 渗透测试学习手册 第一章 Androi
  5. Macaca自动化测试Android和IOS应用
  6. @+id/android:list"和"@android:id/list"
  7. Android服务器通信的几种方式详解
  8. 如何将android view的位置设为右下角
  9. 【译】Google官方推出的Android架构组件
  10. Android 你应该知道的学习资源 进阶之路