Android Message Handling Mechanism

转自:http://solarex.github.io/blog/2015/09/22/android-message-handling-mechanism/

Android is a message driven, message driven several elements:

  • The message says: Message
  • Message queue: MessageQueue
  • The news cycle, remove the message processing for circulation: Looper
  • Message processing, message loop out messages from the message queue should be carried out after the processing of messages: Handler

Usually we use most often is Message and Handler, if you use HandlerThread or similar HandlerThread things may come into contact with Looper, while MessageQueue is used inside Looper, for the standard SDK, we are unable to instantiate and use (constructor is package visibility).    We usually come into contact with Looper,MessageHandler are realized by JAVA, Android for Linux based systems, the bottom with a C, C++, and NDK exist, how could the message driven model only exists in the JAVA layer, in fact, there are corresponding to the Java layer such as LooperMessageQueue in the Native layer.

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

  • 消息的表示:Message
  • 消息队列:MessageQueue
  • 消息循环,用于循环取出消息进行处理:Looper
  • 消息处理,消息循环从消息队列中取出消息后要对消息进行处理:Handler

平时我们最常使用的就是Message与Handler了,如果使用过HandlerThread或者自己实现类似HandlerThread的东西可能还会接触到Looper,而MessageQueue是Looper内部使用的,对于标准的SDK,我们是无法实例化并使用的(构造函数是包可见性)。

我们平时接触到的Looper、Message、Handler都是用JAVA实现的,Android做为基于Linux的系统,底层用C、C++实现的,而且还有NDK的存在,消息驱动的模型怎么可能只存在于JAVA层,实际上,在Native层存在与Java层对应的类如Looper、MessageQueue等。

 

 

Initialization message queue

 

First to see if a thread to achieve the message loop should do, taking HandlerThread as an example:

首先来看一下如果一个线程想实现消息循环应该怎么做,以HandlerThread为例:

 

1
2
3
4
5
6 7 8 9 10 11 12 
public void run() {  mTid = Process.myTid();  Looper.prepare(); //red mark  synchronized (this) {  mLooper = Looper.myLooper();  notifyAll();  }  Process.setThreadPriority(mPriority);  onLooperPrepared();  Looper.loop(); //red mark  mTid = 1; } 

 

In the red mark of the two, first call prepare to initialize the MessageQueue and Looper, and then call the loop enter the message loop. First look at the Looper.prepare.

主要是红色标明的两句,首先调用prepare初始化MessageQueue与Looper,然后调用loop进入消息循环。先看一下Looper.prepare。

 

1
2
3
4
5
6 7 8 9 10 
public static void prepare() {  prepare(true); }  private static void prepare(boolean quitAllowed) {  if (sThreadLocal.get() != null) {  throw new RuntimeException("Only one Looper may be created per thread");  }  sThreadLocal.set(new Looper(quitAllowed)); } 

 

Overloaded functions, quitAllowed default to true, from the name can be seen is whether the message loop can exit, the default is to exit, the Main thread (UI thread) initialization message loop is called prepareMainLooper, pass is false. The use of ThreadLocal, each thread can initialize a Looper.

Look at the Looper in the initialization did:

重载函数,quitAllowed默认为true,从名字可以看出来就是消息循环是否可以退出,默认是可退出的,Main线程(UI线程)初始化消息循环时会调用prepareMainLooper,传进去的是false。使用了ThreadLocal,每个线程可以初始化一个Looper。

再来看一下Looper在初始化时都做了什么:

 

1
2
3
4
5
6 7 8 9 10 
private Looper(boolean quitAllowed) {  mQueue = new MessageQueue(quitAllowed);  mRun = true;  mThread = Thread.currentThread(); }  MessageQueue(boolean quitAllowed) {  mQuitAllowed = quitAllowed;  nativeInit(); } 

 

In the Looper initialization, a MessageQueue object created saved in the mQueue member. The MessageQueueconstructor is package visibility, so we cannot be used directly, while the MessageQueue initialization is called thenativeInit, which is a Native method:

在Looper初始化时,新建了一个MessageQueue的对象保存了在成员mQueue中。MessageQueue的构造函数是包可见性,所以我们是无法直接使用的,在MessageQueue初始化的时候调用了nativeInit,这是一个Native方法:

 

1
2
3
4
5
6 7 8 9 10 11 12 13 14 15 16 
static void android_os_MessageQueue_nativeInit(JNIEnv env, jobject obj) {  NativeMessageQueue nativeMessageQueue = new NativeMessageQueue();  if (!nativeMessageQueue) {  jniThrowRuntimeException(env, "Unable to allocate native queue");  return;  }   nativeMessageQueue–>incStrong(env);  android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue); }  static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv env, jobject messageQueueObj,  NativeMessageQueue nativeMessageQueue) {  env–>SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,  reinterpret_cast<jint>(nativeMessageQueue)); } 

 

In nativeInit, the new object of a Native layer MessageQueue, and the address stored in the Java layer of theMessageQueue member of the mPtr, there are a lot of implementation of Android, a class has been implemented in Java layer and Native layer, the GetFieldID and SetIntField JNI saved Native layer class an address to the Java layer for an instance of the class mPtr members, such as Parcel.

Then the realization of NativeMessageQueue:

在nativeInit中,new了一个Native层的MessageQueue的对象,并将其地址保存在了Java层MessageQueue的成员mPtr中,Android中有好多这样的实现,一个类在Java层与Native层都有实现,通过JNI的GetFieldID与SetIntField把Native层的类的实例地址保存到Java层类的实例的mPtr成员中,比如Parcel。

再看NativeMessageQueue的实现:

 

1
2
3
4
5
6 7 
NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {  mLooper = Looper::getForThread();  if (mLooper == NULL) {  mLooper = new Looper(false);  Looper::setForThread(mLooper);  } } 

 

Gets a Native layer of the Looper object in the constructor of the NativeMessageQueue, Native layer Looper also use thread local storage, note that new Looper introduced parameter false.

在NativeMessageQueue的构造函数中获得了一个Native层的Looper对象,Native层的Looper也使用了线程本地存储,注意new Looper时传入了参数false。

 

1
2
3
4
5
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
Looper::Looper(bool allowNonCallbacks) :  mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),  mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {  int wakeFds[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);   struct epoll_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 layer in Looper using epoll. Initializes a pipeline, mWakeWritePipeFd and mWakeReadPipeFd were preserved to write and read end of pipe end, and monitor the read end of the EPOLLIN event. Note the initializer list of values, the value of mAllowNonCallbacks for false.

What is mAllowNonCallback? The use of epoll to monitor mWakeReadPipeFd events? In fact, Native Looper can not only monitor the descriptors, Looper also provides the addFd method:

Native层的Looper使用了epoll。初始化了一个管道,用mWakeWritePipeFd与mWakeReadPipeFd分别保存了管道的写端与读端,并监听了读端的EPOLLIN事件。注意下初始化列表的值,mAllowNonCallbacks的值为false。

mAllowNonCallback是做什么的?使用epoll仅为了监听mWakeReadPipeFd的事件?其实Native Looper不仅可以监听这一个描述符,Looper还提供了addFd方法:

 

1
2
int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void data); int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void data); 

 

fd said to monitor descriptor. ident said to monitor event identification, Value must be >=0 or be ALOOPER_POLL_BACK(-2), event said to monitor events, callback is a callback function when the event occurs, This is the role of mAllowNonCallbacks, When the mAllowNonCallbacks is true allows callback to NULL, ident inpollOnce as a result of return, Otherwise, do not allow the callback is empty, When the callback is not NULL, The value of ident will be ignored. Or just look at the code easy to understand:

fd表示要监听的描述符。ident表示要监听的事件的标识,值必须>=0或者为ALOOPER_POLL_CALLBACK(-2),event表示要监听的事件,callback是事件发生时的回调函数,mAllowNonCallbacks的作用就在于此,当mAllowNonCallbacks为true时允许callback为NULL,在pollOnce中ident作为结果返回,否则不允许callback为空,当callback不为NULL时,ident的值会被忽略。还是直接看代码方便理解:

 

1
2
3
4
5
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) { #if DEBUG_CALLBACKS  ALOGD("%p ~ addFd – fd=%d, ident=%d, events=0x%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;  }   int epollEvents = 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;   struct epoll_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) {  int 

转载于:https://www.cnblogs.com/dirt2/p/6185143.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值