Android的消息机制
一、简介
Android的消息机制主要是指Handler的运行机制,那么什么是Handler的运行机制那?通俗的来讲就是,使用Handler将子线程的Message放入主线程的Messagequeue中,在主线程使用。
二、学习内容
学习Android的消息机制,我们需要先了解如下内容。
- 消息的表示:Message
- 消息队列:MessageQueue
- 消息循环,用于循环取出消息进行处理:Looper
- 消息处理,消息循环从消息队列中取出消息后要对消息进行处理:Handler
平常我们接触的大多是Handler和Message,今天就让我们来深入的了解一下他们。
三、代码详解
一般而言我们都是这样使用Handler的
xxHandler.sendEmptyMessage(xxx);
当然还有其他表示方法,但我们深入到源代码中,会发现,他们最终都调用了一个方法
publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){ MessageQueuequeue=mQueue; if(queue==null){ RuntimeExceptione=newRuntimeException( this+"sendMessageAtTime()calledwithnomQueue"); Log.w("Looper",e.getMessage(),e); returnfalse; } returnenqueueMessage(queue,msg,uptimeMillis); }
sendMessageAtTime()方法,但这依然不是结束,我们可以看到最后一句enqueueMessage(queue,msg,uptimeMillis);按字面意思来说插入一条消息,那么疑问来了,消息插入了哪里。
booleanenqueueMessage(Messagemsg,longwhen){ if(msg.target==null){ thrownewIllegalArgumentException("Messagemusthaveatarget."); } if(msg.isInUse()){ thrownewIllegalStateException(msg+"Thismessageisalreadyinuse."); } synchronized(this){ if(mQuitting){ IllegalStateExceptione=newIllegalStateException( msg.target+"sendingmessagetoaHandleronadeadthread"); Log.w(TAG,e.getMessage(),e); msg.recycle(); returnfalse; } msg.markInUse(); msg.when=when; Messagep=mMessages; booleanneedWake; 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.next prev.next=msg; } //WecanassumemPtr!=0becausemQuittingisfalse. if(needWake){ nativeWake(mPtr); } } returntrue; }
进入源代码,我们发现,我们需要了解一个新类Messagequeue。
虽然我们一般把他叫做消息队列,但是通过研究,我们发下,它实际上是一种单链表的数据结构,而我们对它的操作主要是插入和读取。
看代码33-44,学过数据结构,我们可以轻松的看出,这是一个单链表的插入末尾的操作。
这样就明白了,我们send方法实质就是向Messagequeue中插入这么一条消息,那么另一个问题随之而来,我们该如何处理这条消息。
处理消息我们离不开一个重要的,Looper。那么它在消息机制中又有什么样的作用那?
Looper扮演着消息循环的角色,具体而言它会不停的从MessageQueue中查看是否有新消息如果有新消息就会立刻处理,否则就已知阻塞在那里,现在让我们来看一下他的代码实现。
首先是构造方法
privateLooper(booleanquitAllowed){ mQueue=newMessageQueue(quitAllowed); mThread=Thread.currentThread(); }
可以发现,它将当前线程对象保存了起来。我们继续
Looper在新线程创建过程中有两个重要的方法looper.prepare()looper.loop
newThread(){ publicvoidrun(){ Looper.prepare(); Handlerhandler=newHandler(); Looper.loop(); } }.start();
我们先来看prepare()方法
privatestaticvoidprepare(booleanquitAllowed){ if(sThreadLocal.get()!=null){ thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread"); } sThreadLocal.set(newLooper(quitAllowed)); }
咦,我们可以看到这里面又有一个ThreadLocal类,我们在这简单了解一下,他的特性,set(),get()方法。
首先ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储后,只有在制定线程中可以获取存储的数据,对于其他线程而言则无法获取到数据。简单的来说。套用一个列子:
privateThreadLocal<Boolean>mBooleanThreadLocal=newThreadLocal<Boolean>();// mBooleanThreadLocal.set(true); Log.d(TAH,"Threadmain"+mBooleanThreadLocal.get()); newThread("Thread#1"){ publicvoidrun(){ mBooleanThreadLocal.set(false); Log.d(TAH,"Thread#1"+mBooleanThreadLocal.get()); }; }.start(); newThread("Thread#2"){ publicvoidrun(){ Log.d(TAH,"Thread#2"+mBooleanThreadLocal.get()); }; }.start();
上面的代码运行后,我们会发现,每一个线程的值都是不同的,即使他们访问的是同意个ThreadLocal对象。
那么我们接下来会在之后分析源码,为什么他会不一样。现在我们跳回prepare()方法那一步,loop()方法源码贴上
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();//mightblock if(msg==null){ //Nomessageindicatesthatthemessagequeueisquitting. return; } //Thismustbeinalocalvariable,incaseaUIeventsetsthelogger Printerlogging=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.recycleUnchecked(); } }
首先loop()方法,获得这个线程的Looper,若没有抛出异常。再获得新建的Messagequeue,在这里我们有必要补充一下Messagequeue的next()方法。
Messagenext(){ //Returnhereifthemessageloophasalreadyquitandbeendisposed. //Thiscanhappeniftheapplicationtriestorestartalooperafterquit //whichisnotsupported. finallongptr=mPtr; if(ptr==0){ returnnull; } intpendingIdleHandlerCount=-1;//-1onlyduringfirstiteration intnextPollTimeoutMillis=0; for(;;){ if(nextPollTimeoutMillis!=0){ Binder.flushPendingCommands(); } nativePollOnce(ptr,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(DEBUG)Log.v(TAG,"Returningmessage:"+msg); msg.markInUse(); returnmsg; } }else{ //Nomoremessages. nextPollTimeoutMillis=-1; } //Processthequitmessagenowthatallpendingmessageshavebeenhandled. if(mQuitting){ 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;//releasethereferencetothehandler booleankeep=false; try{ keep=idler.queueIdle(); }catch(Throwablet){ Log.wtf(TAG,"IdleHandlerthrewexception",t); } if(!keep){ synchronized(this){ mIdleHandlers.remove(idler); } } } //Resettheidlehandlercountto0sowedonotrunthemagain. pendingIdleHandlerCount=0; //Whilecallinganidlehandler,anewmessagecouldhavebeendelivered //sogobackandlookagainforapendingmessagewithoutwaiting. nextPollTimeoutMillis=0; } }
从24-30我们可以看到,他遍历了整个queue找到msg,若是msg为null,我们可以看到50,他把nextPollTimeoutMillis=-1;实际上是等待enqueueMessage的nativeWake来唤醒。较深的源码涉及了native层代码,有兴趣可以研究一下。简单来说next()方法,在有消息是会返回这条消息,若没有,则阻塞在这里。
我们回到loop()方法27msg.target.dispatchMessage(msg);我们看代码
publicvoiddispatchMessage(Messagemsg){ if(msg.callback!=null){ handleCallback(msg); }else{ if(mCallback!=null){ if(mCallback.handleMessage(msg)){ return; } } handleMessage(msg); } }
msg.target实际上就是发送这条消息的Handler,我们可以看到它将msg交给dispatchMessage(),最后调用了我们熟悉的方法handleMessage(msg);
三、总结
到目前为止,我们了解了android的消息机制流程,但它实际上还涉及了深层的native层方法.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!