Android消息循环机制源码深入理解
Android消息循环机制源码
前言:
搞Android的不懂Handler消息循环机制,都不好意思说自己是Android工程师。面试的时候一般也都会问这个知识点,但是我相信大多数码农肯定是没有看过相关源码的,顶多也就是网上搜搜,看看别人的文章介绍。学姐不想把那个万能的关系图拿出来讨论。
近来找了一些关于android线程间通信的资料,整理学习了一下,并制作了一个简单的例子。
andriod提供了Handler和Looper来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。
在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个事android的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handle,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,消息的的处理,把这些都封装在Handle里面,注意Handle只是针对那些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。
但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。
在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个是android的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handler,我们有消息循环,就要往消息循环里面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,把这些都封装在Handler里面,注意Handler只是针对那些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。
但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。
先从我们平时的使用方法引出这个机制,再结合源码进行分析。
我们平时使用是这样的:
//1.主线程 Handlerhandler=newMyHandler(); //2.非主线程 HandlerThreadhandlerThread=newHandlerThread("handlerThread"); handlerThread.start(); Handlerhandler=newHandler(handlerThread.getLooper()); //发送消息 handler.sendMessage(msg); //接收消息 staticclassMyHandlerextendsHandler{ //对于非主线程处理消息需要传Looper,主线程有默认的sMainLooper publicMyHandler(Looperlooper){ super(looper); } @Override publicvoidhandleMessage(Messagemsg){ super.handleMessage(msg); } }
那么为什么初始化的时候,我们执行了1或2,后面只需要sendMessage就可处理任务了呢?学姐这里以非主线程为例进行介绍,handlerThread.start()的时候,实际上创建了一个用于消息循环的Looper和消息队列MessageQueue,同时启动了消息循环,并将这个循环传给Handler,这个循环会从MessageQueue中依次取任务出来执行。用户若要执行某项任务,只需要调用handler.sendMessage即可,这里做的事情是将消息添加到MessaeQueue中。对于主线程也类似,只是主线程sMainThread和sMainLooper不需要我们主动去创建,程序启动的时候Application就创建好了,我们只需要创建Handler即可。
我们这里提到了几个概念:
- HandlerThread支持消息循环的线程
- Handler消息处理器
- Looper消息循环对象
- MessageQueue消息队列
- Message消息体
对应关系是:一对多,即(一个)HandlerThread、Looper、MessageQueue->(多个)Handler、Message
源码解析
1.Looper
(1)创建消息循环
prepare()用于创建Looper消息循环对象。Looper对象通过一个成员变量ThreadLocal进行保存。
(2)获取消息循环对象
myLooper()用于获取当前消息循环对象。Looper对象从成员变量ThreadLocal中获取。
(3)开始消息循环
loop()开始消息循环。循环过程如下:
每次从消息队列MessageQueue中取出一个Message
使用Message对应的Handler处理Message
已处理的Message加到本地消息池,循环复用
循环以上步骤,若没有消息表明消息队列停止,退出循环
publicstaticvoidprepare(){ prepare(true); } privatestaticvoidprepare(booleanquitAllowed){ if(sThreadLocal.get()!=null){ thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread"); } sThreadLocal.set(newLooper(quitAllowed)); } publicstaticLoopermyLooper(){ returnsThreadLocal.get(); } 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("<<<<2.Handler
(1)发送消息
Handler支持2种消息类型,即Runnable和Message。因此发送消息提供了post(Runnabler)和sendMessage(Messagemsg)两个方法。从下面源码可以看出Runnable赋值给了Message的callback,最终也是封装成Message对象对象。学姐个人认为外部调用不统一使用Message,应该是兼容Java的线程任务,学姐认为这种思想也可以借鉴到平常开发过程中。发送的消息都会入队到MessageQueue队列中。
(2)处理消息
Looper循环过程的时候,是通过dispatchMessage(Messagemsg)对消息进行处理。处理过程:先看是否是Runnable对象,如果是则调用handleCallback(msg)进行处理,最终调到Runnable.run()方法执行线程;如果不是Runnable对象,再看外部是否传入了Callback处理机制,若有则使用外部Callback进行处理;若既不是Runnable对象也没有外部Callback,则调用handleMessage(msg),这个也是我们开发过程中最常覆写的方法了。
(3)移除消息
removeCallbacksAndMessages(),移除消息其实也是从MessageQueue中将Message对象移除掉。
publicvoidhandleMessage(Messagemsg){ } publicvoiddispatchMessage(Messagemsg){ if(msg.callback!=null){ handleCallback(msg); }else{ if(mCallback!=null){ if(mCallback.handleMessage(msg)){ return; } } handleMessage(msg); } } privatestaticvoidhandleCallback(Messagemessage){ message.callback.run(); } publicfinalMessageobtainMessage() { returnMessage.obtain(this); } publicfinalbooleanpost(Runnabler) { returnsendMessageDelayed(getPostMessage(r),0); } publicfinalbooleansendMessage(Messagemsg) { returnsendMessageDelayed(msg,0); } privatestaticMessagegetPostMessage(Runnabler){ Messagem=Message.obtain(); m.callback=r; returnm; } publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis) { if(delayMillis<0){ delayMillis=0; } returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis); } publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){ MessageQueuequeue=mQueue; if(queue==null){ RuntimeExceptione=newRuntimeException( this+"sendMessageAtTime()calledwithnomQueue"); Log.w("Looper",e.getMessage(),e); returnfalse; } returnenqueueMessage(queue,msg,uptimeMillis); } privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){ msg.target=this; if(mAsynchronous){ msg.setAsynchronous(true); } returnqueue.enqueueMessage(msg,uptimeMillis); } publicfinalvoidremoveCallbacksAndMessages(Objecttoken){ mQueue.removeCallbacksAndMessages(this,token); }3.MessageQueue
(1)消息入队
消息入队方法enqueueMessage(Messagemsg,longwhen)。其处理过程如下:
待入队的Message标记为InUse,when赋值
若消息链表mMessages为空为空,或待入队Message执行时间小于mMessage链表头,则待入队Message添加到链表头
若不符合以上条件,则轮询链表,根据when从低到高的顺序,插入链表合适位置
(2)消息轮询
next()依次从MessageQueue中取出Message
(3)移除消息
removeMessages()可以移除消息,做的事情实际上就是将消息从链表移除,同时将移除的消息添加到消息池,提供循环复用。
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("MessageQueue",e.getMessage(),e); msg.recycle(); returnfalse; } msg.markInUse(); msg.when=when; Messagep=mMessages; booleanneedWake; if(p==null||when==0||when4.Message
(1)消息创建
Message.obtain()创建消息。若消息池链表sPool不为空,则从sPool中获取第一个,flags标记为UnInUse,同时从sPool中移除,sPoolSize减1;若消息池链表sPool为空,则newMessage()
(2)消息释放
recycle()将消息释放,从内部实现recycleUnchecked()可知,将flags标记为InUse,其他各种状态清零,同时将Message添加到sPool,且sPoolSize加1
/** *ReturnanewMessageinstancefromtheglobalpool.Allowsusto *avoidallocatingnewobjectsinmanycases. */ publicstaticMessageobtain(){ synchronized(sPoolSync){ if(sPool!=null){ Messagem=sPool; sPool=m.next; m.next=null; m.flags=0;//clearin-useflag sPoolSize--; returnm; } } returnnewMessage(); } /** *ReturnaMessageinstancetotheglobalpool. **YouMUSTNOTtouchtheMessageaftercallingthisfunctionbecauseithas *effectivelybeenfreed.Itisanerrortorecycleamessagethatiscurrently *enqueuedorthatisintheprocessofbeingdeliveredtoaHandler. *
*/ publicvoidrecycle(){ if(isInUse()){ if(gCheckRecycle){ thrownewIllegalStateException("Thismessagecannotberecycledbecauseit" +"isstillinuse."); } return; } recycleUnchecked(); } /** *RecyclesaMessagethatmaybein-use. *UsedinternallybytheMessageQueueandLooperwhendisposingofqueuedMessages. */ voidrecycleUnchecked(){ //Markthemessageasinusewhileitremainsintherecycledobjectpool. //Clearoutallotherdetails. flags=FLAG_IN_USE; what=0; arg1=0; arg2=0; obj=null; replyTo=null; sendingUid=-1; when=0; target=null; callback=null; data=null; synchronized(sPoolSync){ if(sPoolSize5.HandlerThread
由于Java中的Thread是没有消息循环机制的,run()方法执行完,线程则结束。HandlerThread通过使用Looper实现了消息循环,只要不主动调用HandlerThread或Looper的quit()方法,循环就是一直走下去。
publicclassHandlerThreadextendsThread{ intmPriority; intmTid=-1; LoopermLooper; publicHandlerThread(Stringname){ super(name); mPriority=Process.THREAD_PRIORITY_DEFAULT; } @Override publicvoidrun(){ mTid=Process.myTid(); Looper.prepare(); synchronized(this){ mLooper=Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid=-1; } publicLoopergetLooper(){ if(!isAlive()){ returnnull; } //Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated. synchronized(this){ while(isAlive()&&mLooper==null){ try{ wait(); }catch(InterruptedExceptione){ } } } returnmLooper; } publicbooleanquit(){ Looperlooper=getLooper(); if(looper!=null){ looper.quit(); returntrue; } returnfalse; } }总结
- 关键类:HandlerThread、Handler、Looper、MessageQueue、Messaga
- MessageQueue数据结构,链表。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!