1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android应用程序消息处理机制(Looper Handler)分析(5)

Android应用程序消息处理机制(Looper Handler)分析(5)

时间:2022-12-10 18:25:55

相关推荐

Android应用程序消息处理机制(Looper Handler)分析(5)

ActivityThread类的这个mH成员变量是什么时候创建的呢?我们前面在分析应用程序的消息循环时,说到当应用程序进程启动之后,就会加载ActivityThread类的main函数里面,在这个main函数里面,在通过Looper类进入消息循环之前,会在当前进程中创建一个ActivityThread实例:

publicfinalclassActivityThread{......publicstaticfinalvoidmain(String[]args){......ActivityThreadthread=newActivityThread();thread.attach(false);......}}

在创建这个实例的时候,就会同时创建其成员变量mH了:

publicfinalclassActivityThread{......finalHmH=newH();......}

前面说过,H类继承于Handler类,因此,当创建这个H对象时,会调用Handler类的构造函数,这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中:

publicclassHandler{......publicHandler(){......mLooper=Looper.myLooper();......mQueue=mLooper.mQueue;......}finalMessageQueuemQueue;finalLoopermLooper;......}

在Hanlder类的构造函数中,主要就是初始成员变量mLooper和mQueue了。这里的myLooper是Looper类的静态成员函数,通过它来获得一个Looper对象,这个Looper对象就是前面我们在分析消息循环时,在ActivityThread类的main函数中通过Looper.prepareMainLooper函数创建的。Looper.myLooper函数实现在frameworks/base/core/java/android/os/Looper.java文件中:

publicclassLooper{......publicstaticfinalLoopermyLooper(){return(Looper)sThreadLocal.get();}......}

有了这个Looper对象后,就可以通过Looper.mQueue来访问应用程序的消息队列了。

有了这个Handler对象mH后,就可以通过它来往应用程序的消息队列中加入新的消息了。回到前面的queueOrSendMessage函数中,当它准备好了一个Message对象msg后,就开始调用mH.sendMessage函数来发送消息了,这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中:

publicclassHandler{......publicfinalbooleansendMessage(Messagemsg){returnsendMessageDelayed(msg,0);}publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis){if(delayMillis<0){delayMillis=0;}returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);}publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){booleansent=false;MessageQueuequeue=mQueue;if(queue!=null){msg.target=this;sent=queue.enqueueMessage(msg,uptimeMillis);}else{......}returnsent;}......}

在发送消息时,是可以指定消息的处理时间的,但是通过sendMessage函数发送的消息的处理时间默认就为当前时间,即表示要马上处理,因此,从sendMessage函数中调用sendMessageDelayed函数,传入的时间参数为0,表示这个消息不要延时处理,而在sendMessageDelayed函数中,则会先获得当前时间,然后加上消息要延时处理的时间,即得到这个处理这个消息的绝对时间,然后调用sendMessageAtTime函数来把消息加入到应用程序的消息队列中去。

在sendMessageAtTime函数,首先得到应用程序的消息队列mQueue,这是在Handler对象构造时初始化好的,前面已经分析过了,接着设置这个消息的目标对象target,即这个消息最终是由谁来处理的:

msg.target=this;

这里将它赋值为this,即表示这个消息最终由这个Handler对象来处理,即由ActivityThread对象的mH成员变量来处理。

函数最后调用queue.enqueueMessage来把这个消息加入到应用程序的消息队列中去,这个函数实现在frameworks/base/core/java/android/os/MessageQueue.java文件中:

publicclassMessageQueue{......finalbooleanenqueueMessage(Messagemsg,longwhen){......finalbooleanneedWake;synchronized(this){......msg.when=when;//Log.d("MessageQueue","Enqueing:"+msg);Messagep=mMessages;if(p==null||when==0||when<p.when){msg.next=p;mMessages=msg;needWake=mBlocked;//newhead,mightneedtowakeup}else{Messageprev=null;while(p!=null&&p.when<=when){prev=p;p=p.next;}msg.next=prev.next;prev.next=msg;needWake=false;//stillwaitingonhead,noneedtowakeup}}if(needWake){nativeWake(mPtr);}returntrue;}......}

把消息加入到消息队列时,分两种情况,一种当前消息队列为空时,这时候应用程序的主线程一般就是处于空闲等待状态了,这时候就要唤醒它,另一种情况是应用程序的消息队列不为空,这时候就不需要唤醒应用程序的主线程了,因为这时候它一定是在忙着处于消息队列中的消息,因此不会处于空闲等待的状态。

第一种情况比较简单,只要把消息放在消息队列头就可以了:

msg.next=p;mMessages=msg;needWake=mBlocked;//newhead,mightneedtowakeup

第二种情况相对就比较复杂一些了,前面我们说过,当往消息队列中发送消息时,是可以指定消息的处理时间的,而消息队列中的消息,就是按照这个时间从小到大来排序的,因此,当把新的消息加入到消息队列时,就要根据它的处理时间来找到合适的位置,然后再放进消息队列中去:

Messageprev=null;while(p!=null&&p.when<=when){prev=p;p=p.next;}msg.next=prev.next;prev.next=msg;needWake=false;//stillwaitingonhead,noneedtowakeup

把消息加入到消息队列去后,如果应用程序的主线程正处于空闲等待状态,就需要调用natvieWake函数来唤醒它了,这是一个JNI方法,定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:

staticvoidandroid_os_MessageQueue_nativeWake(JNIEnv*env,jobjectobj,jintptr){NativeMessageQueue*nativeMessageQueue=reinterpret_cast<NativeMessageQueue*>(ptr);returnnativeMessageQueue->wake();}

这个JNI层的NativeMessageQueue对象我们在前面分析消息循环的时候创建好的,保存在Java层的MessageQueue对象的mPtr成员变量中,这里把它取回来之后,就调用它的wake函数来唤醒应用程序的主线程,这个函数也是定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:

voidNativeMessageQueue::wake(){mLooper->wake();}

这里它又通过成员变量mLooper的wake函数来执行操作,这里的mLooper成员变量是一个C++层实现的Looper对象,它定义在frameworks/base/libs/utils/Looper.cpp文件中:

voidLooper::wake(){......ssize_tnWrite;do{nWrite=write(mWakeWritePipeFd,"W",1);}while(nWrite==-1&&errno==EINTR);.......}

这个wake函数很简单,只是通过打开文件描述符mWakeWritePipeFd往管道的写入一个"W"字符串。其实,往管道写入什么内容并不重要,往管道写入内容的目的是为了唤醒应用程序的主线程。前面我们在分析应用程序的消息循环时说到,当应用程序的消息队列中没有消息处理时,应用程序的主线程就会进入空闲等待状态,而这个空闲等待状态就是通过调用这个Looper类的pollInner函数来进入的,具体就是在pollInner函数中调用epoll_wait函数来等待管道中有内容可读的。

这时候既然管道中有内容可读了,应用程序的主线程就会从这里的Looper类的pollInner函数返回到JNI层的nativePollOnce函数,最后返回到Java层中的MessageQueue.next函数中去,这里它就会发现消息队列中有新的消息需要处理了,于就会处理这个消息。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。