Android消息处理惩罚机制(Handler、Looper、MessageQueue与Message)

本文详细介绍了Android消息驱动的四个核心要素:Message、MessageQueue、Looper和Handler。通过分析HandlerThread的run方法,揭示了Looper.prepare和Looper.loop在初始化消息队列和启动消息循环中的作用。此外,还深入探讨了Native层的MessageQueue和Looper的实现,包括NativeMessageQueue的创建、管道的使用以及epoll事件监听。文章还解释了消息的发送、异步消息、屏障和唤醒机制,展示了消息如何从Java层到Native层的流转过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Android是消息驱动的,实现消息驱动有几个要素:

(1)消息的默示:Message
2 消息队列:MessageQueue
3 消息轮回,用于轮回取出消息进行处理惩罚:Looper
4 消息处理惩罚,消息轮回从消息队列中取出消息后要对消息进行处理惩罚:Handler

  日常平凡我们最常应用的就是Message与Handler了,若是应用过HandlerThread或者本身实现类似HandlerThread的器材可能还会接触到Looper,而MessageQueue是Looper内部应用的,对于标准的SDK,我们是无法实例化并应用的(机关函数是包可见性)。
  我们日常平凡接触到的Looper、Message、Handler都是用JAVA实现的,Android做为基于Linux的体系,底层用C、C++实现的,并且还有NDK的存在,消息驱动的模型怎么可能只存在于JAVA层,实际上,在Native层存在与Java层对应的类如Looper、MessageQueue等。
 初始化消息队列
  起首来看一下若是一个线程想实现消息轮回应当怎么做,以HandlerThread为例:

publicvoidrun() {
mTid=Process.myTid();
Looper.prepare();
synchronized(this) {
mLooper=Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid= -1;


  主如果红色标明的两句,起首调用prepare初始化MessageQueue与Looper,然后调用loop进入消息轮回。先看一下Looper.prepare。

publicstaticvoidprepare() {
prepare(true);
}

privatestaticvoidprepare(booleanquitAllowed) {
if(sThreadLocal.get() !=null) {
thrownewRuntimeException("Only one Looper may be created per thread");
}
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, jobject obj) {
NativeMessageQueue* nativeMessageQueue =newNativeMessageQueue();
if(!nativeMessageQueue) {
jniThrowRuntimeException(env,"Unable to allocate native queue");
return;
}

nativeMessageQueue->incStrong(env);
android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}

staticvoidandroid_os_MessageQueue_setNativeMessageQueue(JNIEnv*env, jobject messageQueueObj,
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也应用了线程本地存储,重视new Looper时传入了参数false。


Looper::Looper(boolallowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
intwakeFds[2];
int result =pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result!=0,"Could not create wake pipe.  errno=%d", errno);

mWakeReadPipeFd= wakeFds[0];
mWakeWritePipeFd = wakeFds[1];

result=fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result!=0,"Could not make wake read pipe non-blocking.  errno=%d",
errno);

result=fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result!=0,"Could not make wake write pipe non-blocking.  errno=%d",
errno);

//Allocate the epoll instance and register the wake pipe.
mEpollFd =epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd<0,"Could not create epoll instance.  errno=%d", errno);

structepoll_event eventItem;
memset(& eventItem,0,sizeof(epoll_event));//zero out unused members of data field union
eventItem.events =EPOLLIN;
eventItem.data.fd=mWakeReadPipeFd;
result= epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result!=0,"Could not add wake read pipe to epoll instance.  errno=%d",
errno);
}

  Native层的Looper应用了epoll。初始化了一个管道,用mWakeWritePipeFd与mWakeReadPipeFd分别保存了管道的写端与读端,并了读端的EPOLLIN事务。重视下初始化列表的值,mAllowNonCallbacks的值为false。
  mAllowNonCallback是做什么的?应用epoll仅为了mWakeReadPipeFd的事务?其实Native Looper不仅可以这一个描述符,Looper还供给了addFd办法:


intaddFd(intfd,intident,intevents, ALooper_callbackFunc callback,void*data);
intaddFd(intfd,intident,intevents,constsp<LooperCallback>& callback,void* data);

  fd默示要的描述符。ident默示要的事务的标识,值必须>=0或者为ALOOPER_POLL_BACK(-2),event默示要的事务,callback是事务产生时的回调函数,mAllowNonCallbacks的感化就在于此,当mAllowNonCallbacks为true时容许callback为NULL,在pollOnce中ident作为成果返回,不然不容许callback为空,当callback不为NULL时,ident的值会被忽视。还是直接看代码便利懂得:


intLooper::addFd(intfd,intident,intevents,constsp<LooperCallback>& callback,void*data) {
#ifDEBUG_CALLBACKS
ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0 x%x, callback=%p, data=%p",this, fd, ident,
events, callback.get(), data);
#endif
if(!callback.get()) {
if(!mAllowNonCallbacks) {
ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
return-1;
}
if(ident <0) {
ALOGE("Invalid attempt to set NULL callback with ident < 0.");
return-1;
}
}else{
ident=ALOOPER_POLL_CALLBACK;
}

intepollEvents =0;
if(events & ALOOPER_EVENT_INPUT) epollEvents |=EPOLLIN;
if(events & ALOOPER_EVENT_OUTPUT) epollEvents |=EPOLLOUT;

{//acquire lock
AutoMutex _l(mLock);

Request request;
request.fd=fd;
request.ident=ident;
request.callback=callback;
request.data=data;

structepoll_event eventItem;
memset(& eventItem,0,sizeof(epoll_event));//zero out unused members of data field union
eventItem.events =epollEvents;
eventItem.data.fd=fd;

ssize_t requestIndex=mRequests.indexOfKey(fd);
if(requestIndex <0) {
intepollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem);
if(epollResult <0) {
ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
return-1;
}
mRequests.add(fd, request);
}else{
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值