Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx

上传人:b****6 文档编号:19168844 上传时间:2023-01-04 格式:DOCX 页数:29 大小:68.43KB
下载 相关 举报
Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx_第1页
第1页 / 共29页
Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx_第2页
第2页 / 共29页
Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx_第3页
第3页 / 共29页
Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx_第4页
第4页 / 共29页
Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx

《Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx》由会员分享,可在线阅读,更多相关《Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx(29页珍藏版)》请在冰豆网上搜索。

Android消息处理机制HandlerLooperMessageQueue与MessageWord文档格式.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 法学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1