Android消息处理机制(三):进入循环

      消息的处理是一个不间断的过程,所以他实在死循环中进行了。为了节省CPU的资源,当消息队列中没有消息的时候,会在该线程中休眠,等待其他线程的唤醒。下面看一个该过程的时序图。



      下面我们从源码的角度来分析进入消息循环的过程。

frameworks\base\core\java\android\os\Looper.java

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

  	......

    for (;;) {
		/*如果没有消息要处理,则休眠*/
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
		.....
		
    }
}
      Looper类调用loop静态成员函数进入循环,第2行代码得到该线程的Looper对象,第6行代码得到Looper类中的MessageQueue对象,下面是一个死循环,不断在里面处理得到的消息。当没有消息的时候,会调用MessageQueue类的成员函数next使其在线程中休眠。下面我们来看一下MessageQueue类中的next()。

frameworks\base\core\java\android\os\MessageQueue.java

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
	/*pendingIdleHandlerCount保存注册到消息队列中的空闲
	*消息处理器的个数。*/
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
		/*nextPollTimeoutMillis等于0,表示即使消息队列中没有新的消息需要处理,当
		前线程也不要进入睡眠等待状态。若为-1,则表示没有消息处理则立即进入休眠
		状态,直到被其他线程唤醒。*/
        nativePollOnce(ptr, nextPollTimeoutMillis);
		......
		
    }
}
      MessageQueue类的成员变成mPtr是一个地址值,其指向Native层的NativeMessageQueue类的指针。第9行代码定义了另外一个变量nextPollTimeoutMills,用来描述当消息队列中没有新的消息需要处理时,当前线程需要进入休眠等待状态的时间。如果nextPollTimeoutMills的值等于0,那么就表示即使消息队列中没有新的消息需要处理,当前线程也不要进入睡眠等待状态。如果变量nextPollTimeoutMills的值等于-1,那么就表示当消息队列中没有新的消息需要处理时,当前线程需要无限地处于睡眠等待状态,直到它被其他线程唤醒为止。
frameworks\base\core\jni\android_os_MessageQueue.cpp  

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, timeoutMillis);
}
      有上面的参数可知,ptr是一个指向nativeMessageQueue指针,第3行代码故可以得到一个NativeMessageQueue对象。调用nativeMessageQueue类的pollOnce()方法。
frameworks\base\core\jni\android_os_MessageQueue.cpp 

void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
    mInCallback = true;
	/*mLooper指向一个C++层的Looper对象*/
    mLooper->pollOnce(timeoutMillis);
    mInCallback = false;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}
system\core\libutils\Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
    	/*省略的代码以后在分析......*/
        ......
        
        result = pollInner(timeoutMillis);
    }
}
int Looper::pollInner(int timeoutMillis) {
	
	.......
	
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

	......
	
    return result;
}
      第5行代码调用函数epoll_wait来监听注册在前面所创建的epoll实例中的文件描述符的IO读写事件。如果这些文件描述符都没有发生IO读写事件,那么当前线程就会在函数epoll_wait中进入睡眠等待状态,等待的时间由最后一个参数timeoutMillis来指定。从函数epoll_wait返回来之后,接下来第11行到第21行的for循环就检查是哪一个文件描述符发生了IO读写事件。第14行的if语句检查发生IO读写事件的文件描述符是否是与当前线程所关联的一个管道的读端文件描述符mWakeReadPipeFd。如果是,并且它
所发生的IO读写事件的类型为EPOLLIN,那么这时候就说明其他线程向当前线程所关联的一个管道写入一个新的数据。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值