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层方法.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!
