Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx
《Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx》由会员分享,可在线阅读,更多相关《Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx(29页珍藏版)》请在冰豆网上搜索。
mTid=-1;
}
主要是红色标明的两句,首先调用prepare初始化MessageQueue与Looper,然后调用loop进入消息循环。
先看一下Looper.prepare。
publicstaticvoidprepare(){
prepare(true);
}
privatestaticvoidprepare(booleanquitAllowed){
if(sThreadLocal.get()!
=null){
thrownewRuntimeException("
OnlyoneLoopermaybecreatedperthread"
);
sThreadLocal.set(newLooper(quitAllowed));
重载函数,quitAllowed默认为true,从名字可以看出来就是消息循环是否可以退出,默认是可退出的,Main线程(UI线程)初始化消息循环时会调用prepareMainLooper,传进去的是false。
使用了ThreadLocal,每个线程可以初始化一个Looper。
再来看一下Looper在初始化时都做了什么:
privateLooper(booleanquitAllowed){
mQueue=newMessageQueue(quitAllowed);
mRun=true;
mThread=Thread.currentThread();
MessageQueue(booleanquitAllowed){
mQuitAllowed=quitAllowed;
nativeInit();
在Looper初始化时,新建了一个MessageQueue的对象保存了在成员mQueue中。
MessageQueue的构造函数是包可见性,所以我们是无法直接使用的,在MessageQueue初始化的时候调用了nativeInit,这是一个Native方法:
staticvoidandroid_os_MessageQueue_nativeInit(JNIEnv*env,jobjectobj){
NativeMessageQueue*nativeMessageQueue=newNativeMessageQueue();
if(!
nativeMessageQueue){
jniThrowRuntimeException(env,"
Unabletoallocatenativequeue"
return;
nativeMessageQueue->
incStrong(env);
android_os_MessageQueue_setNativeMessageQueue(env,obj,nativeMessageQueue);
staticvoidandroid_os_MessageQueue_setNativeMessageQueue(JNIEnv*env,jobjectmessageQueueObj,
NativeMessageQueue*nativeMessageQueue){
env->
SetIntField(messageQueueObj,gMessageQueueClassInfo.mPtr,
reinterpret_cast<
jint>
(nativeMessageQueue));
在nativeInit中,new了一个Native层的MessageQueue的对象,并将其地址保存在了Java层MessageQueue的成员mPtr中,Android中有好多这样的实现,一个类在Java层与Native层都有实现,通过JNI的GetFieldID与SetIntField把Native层的类的实例地址保存到Java层类的实例的mPtr成员中,比如Parcel。
再看NativeMessageQueue的实现:
NativeMessageQueue:
:
NativeMessageQueue():
mInCallback(false),mExceptionObj(NULL){
mLooper=Looper:
getForThread();
if(mLooper==NULL){
mLooper=newLooper(false);
Looper:
setForThread(mLooper);
在NativeMessageQueue的构造函数中获得了一个Native层的Looper对象,Native层的Looper也使用了线程本地存储,注意newLooper时传入了参数false。
Looper:
Looper(boolallowNonCallbacks):
mAllowNonCallbacks(allowNonCallbacks),mSendingMessage(false),
mResponseIndex(0),mNextMessageUptime(LLONG_MAX){
intwakeFds[2];
intresult=pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result!
=0,"
Couldnotcreatewakepipe.errno=%d"
errno);
mWakeReadPipeFd=wakeFds[0];
mWakeWritePipeFd=wakeFds[1];
result=fcntl(mWakeReadPipeFd,F_SETFL,O_NONBLOCK);
Couldnotmakewakereadpipenon-blocking.errno=%d"
errno);
result=fcntl(mWakeWritePipeFd,F_SETFL,O_NONBLOCK);
Couldnotmakewakewritepipenon-blocking.errno=%d"
//Allocatetheepollinstanceandregisterthewakepipe.
mEpollFd=epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd<
0,"
Couldnotcreateepollinstance.errno=%d"
structepoll_eventeventItem;
memset(&
eventItem,0,sizeof(epoll_event));
//zerooutunusedmembersofdatafieldunion
eventItem.events=EPOLLIN;
eventItem.data.fd=mWakeReadPipeFd;
result=epoll_ctl(mEpollFd,EPOLL_CTL_ADD,mWakeReadPipeFd,&
eventItem);
Couldnotaddwakereadpipetoepollinstance.errno=%d"
Native层的Looper使用了epoll。
初始化了一个管道,用mWakeWritePipeFd与mWakeReadPipeFd分别保存了管道的写端与读端,并监听了读端的EPOLLIN事件。
注意下初始化列表的值,mAllowNonCallbacks的值为false。
mAllowNonCallback是做什么的?
使用epoll仅为了监听mWakeReadPipeFd的事件?
其实NativeLooper不仅可以监听这一个描述符,Looper还提供了addFd方法:
intaddFd(intfd,intident,intevents,ALooper_callbackFunccallback,void*data);
intaddFd(intfd,intident,intevents,constsp<
LooperCallback>
&
callback,void*data);
fd表示要监听的描述符。
ident表示要监听的事件的标识,值必须>
=0或者为ALOOPER_POLL_CALLBACK(-2),event表示要监听的事件,callback是事件发生时的回调函数,mAllowNonCallbacks的作用就在于此,当mAllowNonCallbacks为true时允许callback为NULL,在pollOnce中ident作为结果返回,否则不允许callback为空,当callback不为NULL时,ident的值会被忽略。
还是直接看代码方便理解:
intLooper:
addFd(intfd,intident,intevents,constsp<
callback,void*data){
#ifDEBUG_CALLBACKS
ALOGD("
%p~addFd-fd=%d,ident=%d,events=0x%x,callback=%p,data=%p"
this,fd,ident,
events,callback.get(),data);
#endif
callback.get()){
mAllowNonCallbacks){
ALOGE("
InvalidattempttosetNULLcallbackbutnotallowedforthislooper."
return-1;
if(ident<
0){
InvalidattempttosetNULLcallbackwithident<
0."
}else{
ident=ALOOPER_POLL_CALLBACK;
intepollEvents=0;
if(events&
ALOOPER_EVENT_INPUT)epollEvents|=EPOLLIN;
ALOOPER_EVENT_OUTPUT)epollEvents|=EPOLLOUT;
{//acquirelock
AutoMutex_l(mLock);
Requestrequest;
request.fd=fd;
request.ident=ident;
request.callback=callback;
request.data=data;
eventItem.events=epollEvents;
eventItem.data.fd=fd;
ssize_trequestIndex=mRequests.indexOfKey(fd);
if(requestIndex<
intepollResult=epoll_ctl(mEpollFd,EPOLL_CTL_ADD,fd,&
if(epollResult<
Erroraddingepolleventsforfd%d,errno=%d"
fd,errno);
mRequests.add(fd,request);
intepollResult=epoll_ctl(mEpollFd,EPOLL_CTL_MOD,fd,&
Errormodifyingepolleventsforfd%d,errno=%d"
mRequests.replaceValueAt(requestIndex,request);
}//releaselock
return1;
如果callback为空会检查mAllowNonCallbacks看是否允许callback为空,如果允许callback为空还会检测ident是否>
=0。
如果callback不为空会把ident的值赋值为ALOOPER_POLL_CALLBACK,不管传进来的是什么值。
接下来把传进来的参数值封装到一个Request结构体中,并以描述符为键保存到一个KeyedVectormRequests中,然后通过epoll_ctl添加或替换(如果这个描述符之前有调用addFD添加监听)对这个描述符事件的监听。
类图:
发送消息
通过Looper.prepare初始化好消息队列后就可以调用Looper.loop进入消息循环了,然后我们就可以向消息队列发送消息,消息循环就会取出消息进行处理,在看消息处理之前,先看一下消息是怎么被添加到消息队列的。
在Java层,Message类表示一个消息对象,要发送消息首先就要先获得一个消息对象,Message类的构造函数是public的,但是不建议直接newMessage,Message内部保存了一个缓存的消息池,我们可以用obtain从缓存池获得一个消息,Message使用完后系统会调用recycle回收,如果自己new很多Message,每次使用完后系统放入缓存池,会占用很多内存的,如下所示:
publicstaticMessageobtain(){
synchronized(sPoolSync){
if(sPool!
Messagem=sPool;
sPool=m.next;
m.next=null;
sPoolSize--;
returnm;
returnnewMessage();
publicvoidrecycle(){
clearForRecycle();
if(sPoolSize<
MAX_POOL_SIZE){
next=sPool;
sPool=this;
sPoolSize++;
Message内部通过next成员实现了一个链表,这样sPool就了为了一个Messages的缓存链表。
消息对象获取到了怎么发送呢,大家都知道是通过Handler的post、sendMessage等方法,其实这些方法最终都是调用的同一个方法sendMessageAtTime:
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方法,消息队列mQueue是从与Handler关联的Looper获得的。
privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){
msg.target=this;
if(mAsynchronous){
msg.setAsynchronous(true);
returnqueue.enqueueMessage(msg,uptimeMillis);
enqueueMessage将message的target设置为当前的handler,然后调用MessageQueue的enqueueMessage,在调用queue.enqueueMessage之前判断了mAsynchronous,从名字看是异步消息的意思,要明白Asynchronous的作用,需要先了解一个概念Barrier。
Barrier与AsynchronousMessage
Barrier是什么意思呢,从名字看是一个拦截器,在这个拦截器后面的消息都暂时无法执行,直到这个拦截器被移除了,MessageQueue有一个函数叫enqueueSyncBarier可以添加一个Barrier。
intenqueueSyncBarrier(longwhen){
//Enqueueanewsyncbarriertoken.
//Wedon'
tneedtowakethequeuebecausethepurposeofabarrieristostallit.
finalinttoken=mNextBarrierToken++;
finalMessagemsg=Message.obtain();
msg.arg1=token;
Messageprev=null;
Messagep=mMessages;
if(when!
=0){
while(p!
=null&
p.when<
=when){
prev=p;
p=p.next;
if(prev!
=null){//invariant:
p==prev.next
msg.next=p;
prev.next=msg;
mMessages=msg;
returntoken;
在enqueueSyncBarrier中,obtain了一个Message,并设置msg.arg1=token,token仅是一个每次调用enqueueSyncBarrier时自增的int值,目的是每次调用enqueueSyncBarrier时返回唯一的一个token,这个Message同样需要设置执行时间,然后插入到消息队列,特殊的是这个Message没有设置target,即msg.target为null。
进入消息循环后会不停地从MessageQueue中取消息执行,调用的是MessageQueue的next函数,其中有这么一段:
Messagemsg=mMessages;
if(msg!
msg.target==null){
//Stalledbyabarrier.Findthenextasynchronousmessageinthequeue.
do{
prevMsg=msg;
msg=msg.next;
}while(msg!
!
msg.isAsynchronous());
如果队列头部的消息的target为null就表示它是个Barrier,因为只有两种方法往mMessages中添加消息,一种是enqueueMessage,另一种是enqueueBarrier,而enqueueMessage中如果mst.target为null是直接抛异常的,后面会看到。
所谓的异步消息其实就是这样的,我们可以通过enqueueBarrier往消息队列中插入一个Barrier,那么队列中执行时间在这个Barrier以后的同步消息都会被这个Barrier拦截住无法执行,直到我们调用removeBarrier移除了这个Barrier,而异步消息则没有影响,消息默认就是同步消息,除非我们调用了Message的setAsynchronous,这个方法是隐藏的。
只有在初始化Handler时通过参数指定往这个Handler发送的消息都是异步的,这样在Han