android MessageQueue入门
接触安卓几年了。但是感觉一直不是很明白,东西太多了。反过来说就是自己太菜了。很多东西其实都是模凌两可,不熟悉,很多知识点都是知道一点,最多大家都这样用。没问题,事件长了也一直这样用的。
但是有个问题,安卓在不断的升级,但是自己的知识却升的不多。咋整? 想去全球顶级公司不? 想, 想去是好。但是得把软件开发的路子或者思想弄透彻了。得把实现机制弄懂了。这样估计就用机会了。
我们今天来谈谈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
我一般用他来做垃圾回收。
android MessageQueue入门的更多相关文章
- [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解
原文链接:Hello, Android Multiscreen_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android Multiscreen深入理解. 本 ...
- [译]:Xamarin.Android开发入门——Hello,Android深入理解
返回索引目录 原文链接:Hello, Android_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android深入理解 本部分介绍利用Xamarin开发And ...
- [译]:Xamarin.Android开发入门——Hello,Android快速上手
返回索引目录 原文链接:Hello, Android_Quickstart. 译文链接:Xamarin.Android开发入门--Hello,Android快速上手 本部分介绍利用Xamarin开发A ...
- Hello, Android 快速入门
Hello, Android Android 开发与 Xamarin 简介 在这两节指南中,我们将 (使用 Xamarin Studio或 Visual Studio)建立我们的第一个 Xamarin ...
- Android工程师入门(二)——不忙不累怎么睡。。
安卓开发迫在眉睫,这周入个门吧! Android工程师入门(二) 四.在界面中显示图片 ImageView 是显示图片的一个控件. --属性 src——内容图片: background——背景图片/背 ...
- [电子书] 《Android编程入门很简单》
<Android编程入门很简单>是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书.本书避免出现云山雾罩.晦涩难懂的讲解,代之以轻松活泼.由浅入 ...
- Android实现入门界面布局
Android实现入门界面布局 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 代码实现 首先是常量的定义,安卓中固定字符串应该定义在常量中. stri ...
- Android从入门到精通pdf+书源代码
不须要积分,免费放送 Android从入门到精通的pdf,入门的好书籍,因为csdn文件大小的限制所以分成了两部分. part1地址:http://download.csdn.net/detail/a ...
- 教我徒弟Android开发入门(一)
前言: 这个系列的教程是为我徒弟准备的,也适合还不懂java但是想学android开发的小白们~ 本系列是在Android Studio的环境下运行,默认大家的开发环境都是配置好了的 没有配置好的同学 ...
随机推荐
- Interview with Oleg
Interview with Oleg time limit per test 1 second memory limit per test 256 megabytes input standard ...
- MySQ安装
1.去官网下载安装包 .http://www.mysql.com/downloads/ 2.安装过程中会出现下面的提示:记得保存你的MySQL的初始的默认密码.如果没有注意,那么恢复起来有点麻烦,后续 ...
- HALF<水题>
题意: 找出n/d=0.5的所有数.输入:test,x(代表n的位数,1<=x<=4).并且n和d的每一个位数不能有重复,也不能是0. 输入: 1 1 输出: the form 1/2 = ...
- java内部类继承--构造函数传参
/: innerclasses/InheritInner.java // Inheriting an inner class. class WithInner { class Inner {} } / ...
- shell写多行到文件中
用cat或者echo命令输入多行数据到指定文本 #!/bin/sh ( cat <<EOF start() { echo "start" } EOF ) > Ma ...
- SQL Server 自定义快捷键
SQL Server程序员经常要在SSMS(SQL Server Management Studio)或查询分析器(2000以前)中编写T-SQL代码.以下几个技巧,可以提升工作效率. 以下说明以SS ...
- leetcode371
我这道题目真的是划水的,因为弄了很长时间发现,我可能对于位操作不是特别喜欢吧. 确实为了最求速度,位操作确实快一些. 单独从题目意思来说,用别的方式实现加法,我觉得吧,真的有点醉了...就这样. 下面 ...
- Redis(1)在windows环境下的安装和测试
初次准备使用redis,一个著名的nosql缓存数据库. 这里是第一天,就简单写一下windows下的安装,遇到的一些问题,然后简单的使用和测试,之后会在代码中使用和测试. 之后还会在生产环境中进行测 ...
- C#实现拷贝对象
大家都知道,在C#中变量的存储分为值类型和引用类型两种,而值类型和引用类型在数值变化是产生的后果是不一样的,值类型我们可以轻松实现数值的拷贝,那么引用类型呢,在对象拷贝上存在着一定的难度. 下 ...
- dpkg -P xx
dpkg -l | grep ^rc | cut -d' ' -f3|xargs dpkg -P http://www.linuxquestions.org/questions/debian-26/h ...