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||when
4.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(sPoolSize
5.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数据结构,链表。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!