接触安卓几年了。但是感觉一直不是很明白,东西太多了。反过来说就是自己太菜了。很多东西其实都是模凌两可,不熟悉,很多知识点都是知道一点,最多大家都这样用。没问题,事件长了也一直这样用的。
但是有个问题,安卓在不断的升级,但是自己的知识却升的不多。咋整? 想去全球顶级公司不? 想, 想去是好。但是得把软件开发的路子或者思想弄透彻了。得把实现机制弄懂了。这样估计就用机会了。

我们今天来谈谈Handler Looper Messagequeue的知识。这个东西是入门的东西,也是写安卓应用必备的知识点。但是我怎么感觉还不透彻了。实在不透彻。不管别人怎么样,反正我记录下,最好能学会。

多个handler绑定了一个Looper, 一个looper绑定了一个MessageQueue 臧春杰 marvell 这个都知道。 也知道java通过线程私有变量来保存looper信息。 也就是说一个线程最多有个一个Looper. 系统通过ThreadLocal方法来保存

线程私有变量。

那下面一步就是冲消息队列取消息然后处理消息,如果没有消息就再等待。

我们通过代码可以看到,
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
诡异了。这里有个jni方法,莫非消息队列是通过jni建立的?
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz //臧春杰 marvell) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}

nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
还真是,原来还真是
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
这里出现了我们的主角,这里需要问一句, 线程在消息队列没有消 臧春杰 marvell 息的时候会阻塞,那如何阻塞呢? 是阻塞在java里的吗? 是阻塞这哪里的呢? 可以说就是阻塞在looper里,这里looper.cpp不要和Java层的Looper.java混淆了。

这两个东西毫无关系,记得是毫无关系,陌生人,谁也不认识谁。
那c++这里是如何阻塞的呢? epoll多路监听阻塞,那阻塞的描述符是哪个呢?Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), //臧春杰 marvell
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
mWakeEventFd = eventfd(0, EFD_NONBLOCK);

mWakeEventFd = eventfd(0, EFD_NONBLOCK);就这个,套路啊。慢慢的全是套路,以前不是用pipe的吗?时代在进步,社会在发展,用了eventfd了。

那这就明白了,looper在epoll_wait等待唤醒。那紧接着问题来了,我们经常使用比如5秒后唤醒,那这5秒是如何做到呢?系统如何计时5秒呢?同样也是epoll_wait参 臧春杰 marvell数有个timeout用来计时,
epoll_wait返回值需要说明下。
When successful, epoll_wait() returns the number of file descriptors ready for the requested I/O, or zero if no file
descriptor became ready during the requested timeout milliseconds. When an error occurs, epoll_wait() returns -1 and
errno is set appropriately.
这就是问题的关键。

其实在c++层面,也可以处理消息,也可以监听文件描述符。
int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);
void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message); 臧春杰 marvell
所以我们可以看到,很多在native service中,都使用了这些功能。

那既然在c++层面在监听,那如何唤醒呢? 很简单,就是让文件描述符可读,如何可读? 往文件描述符写东西

void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif

uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
通过这个东西,可以唤醒了。开始做消息处理。这就是为什么消息先处理c++层面的消息,然后再处理java层面的消息。所有的消息处理都根据消息的触发时间来计算的。看当前时间和消息需要触发时间比较。

通过这两个时间来计算timeout时间,这就要求消息队列是排序的,按照触发时间排序。

消息队列补充知识点:

我们听说过桩子臧春杰 marvell的概念。postSyncBarrier,removeSyncBarrier 这个是干什么用呢? 桩子的作用是 桩子后面的消息系统不会处理,直到桩子被拿掉,这是干什么呢?

想想这个场景,我们在主线程干事情,往另一个线程发消息,但是我们得主线程干完,其他线程才能处理消息,那如何保证这个呢? 这就需要桩子,不然cpu 臧春杰 marvell 调度时候,我们不能保证这个消息在什么时候处理。说不定,

sendMessage后,它立马就运行了。

当消息队列没有消息时候,我们可以做点其他事情,
addIdleHandler

我一般用他来做垃圾回收。

最新文章

  1. D3中selection之使用
  2. Opencv基本数据结构
  3. linux下不能使用shutdown命令
  4. hdu 1035 (usage of sentinel, proper utilization of switch and goto to make code neat) 分类: hdoj 2015-06-16 12:33 28人阅读 评论(0) 收藏
  5. JAVA SERVLET专题(上)
  6. sed详解
  7. centos下安装mycat
  8. PHP 扩展库
  9. 安装SQL SERVER2005时,需要win7下安装IIS,记录下
  10. shell如何将文件上传至ftp
  11. SQL中条件放在on后与where后的区别
  12. java_ log4j的基本配置参数
  13. Spring第二天
  14. 使用外部容器运行spring-boot项目:不使用spring-boot内置容器让spring-boot项目运行在外部tomcat容器中
  15. 正确地缩写 document.querySelector
  16. 关于numpy.maximum函数的测试
  17. 圆桌的项目Alpha冲刺(团队)
  18. mysql5.5被django抛弃,安装mysql5.7记录
  19. .“代理XP”组件已作为此服务器安全配置的一部分被关闭的解决办法
  20. asp.net文件上传下载

热门文章

  1. 【最短路】 poj 2387
  2. C++中L和_T()之区别
  3. sqlserver日志文件过大的处理方法
  4. Android开机动画启动流程
  5. CodeForces 670 A. Holidays(模拟)
  6. 转:Selenium2.0之grid学习总结
  7. JavaScript算法与数据结构知识点记录
  8. 利用php函数mkdir递归创建层级目录
  9. 【项目笔记】【bug】数组空指针异常
  10. JS跨域代码