Android 消息队列机制
在非UI线程使用Handler
进行线程通信时,一般都需要进行3个步骤:
- 创建Looper
Looper.prepar()
- 创建
Handler
- 启动消息循环
Looper.loop()
通过这3步,基本就建立好了 Android 的多线程消息通信机制:
- Handler
- MessageQueue
- Looper
- Message
这几者可谓是你中有我,我中有你的存在。通过 Handler 发送 Message 到 Looper 的 MessageQueue 中,待 Looper 的循环执行到 Message 后,就会根据 Message 的 target handler,回调对应 Handler 的 handlerMessage 方法。
例如: Thread-A 拥有一个 Looper,Thread-B 持有一个在 Thread-A 中构造的 Handler,Thread-B 就可以通过这个 Handler 将 Message 发送到 Thread-A 的 Looper 的 MessageQueue 中,然后消息会走到 Thread-A 的 Handler 的 handleMessage 方法。
Looper 原理图
在 Looper 类加载时就会创建一个 ThreadLocal 类型的类变量 sThreadLocal
public final class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper.prepar()
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");
}
// 将构造的 looper 存到类变量 sThreadLocal 中
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
// 构建一个 messageQueue 成员
mQueue = new MessageQueue(quitAllowed);
// 将当前线程存入 mThread 中
mThread = Thread.currentThread();
}
在这里面主要执行了 3 步:
- 构建一个 looper
- 构建一个 messageQueue 成员
- 将当前线程存入 mThread 中
- 将构造的 looper 存到类变量 sThreadLocal 中
至此,执行 Looper.praper 的当前线程就会拥有一个 looper 成员了,存放在 Looper 的 sThreadLocal 中。
创建Handler
public Handler(Callback callback, boolean async) {
...
// 通过`Looper.myLooper()` 类方法获取 sThreadLocal 中储存的当前线程的 looper,将这个 looper 绑定到 handler 的成员变量 mLooper 中
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
// 将 mLooper 中的 messageQueue 绑定到 handler 的成员变量 mQueue 中
mQueue = mLooper.mQueue;
...
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper.loop()
声明一个局部常量
final Loop me = myLoop()
myLoop()
将返回当前线程的looper成员
声明一个局部常量
final MessageQueue queue
- 将me.mQueue赋值给queue
进入无限循环
//进入无限循环
for (;;) {
//取出一条消息
Message msg = queue.next();
//没有消息就阻塞
if (msg == null) {
return;
}
...
//分发消息
try {
msg.target.dispatchMessage(msg);
//msg.target是一个Handler对象
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
//回收消息
msg.recycleUnchecked();
通过
Message.obtain()
获取的消息,需要使用Handler.sendMessage()
插入到消息队列。通过
Handler.obtainMessage()
获取的消息,可以使用message.sendToTaget()
插入到消息队列。
Android 消息队列机制的更多相关文章
- ZWave 中的消息队列机制
文章主题 在我们的日常编程中,对消息队列的需求非常常见,使用一个简洁.高效的消息队列编程模型,对于代码逻辑的清晰性,对于事件处理的高效率来说,是非常重要的.这篇文章就来看看 ZWave 中是通过什 ...
- Android消息队列和Looper
1. 什么是消息队列 消息队列在android中对应MessageQueue这个类,顾名思义,消息队列中存放了大量的消息(Message) 2.什么是消息 消息(Message)代表一个行为(what ...
- Android 消息分发机制
Android 中针对耗时的操作,放在主线程操作,轻者会造成 UI 卡顿,重则会直接无响应,造成 Force Close.同时在 Android 3.0 以后,禁止在主线程进行网络请求. 针对耗时或者 ...
- Android开发学习—— 消息队列
###主线程不能被阻塞* 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差* 主线程阻塞时间过长,系统会抛出ANR异常* ANR:Application ...
- Android 开发笔记 “Android 的消息队列模型”
Android是参考Windows的消息循环机制来实现Android自身的消息循环的. Android通过Looper.Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都 ...
- Android 的消息队列模型
Android 的消息队列模型 Android是参考Windows的消息循环机制来实现Android自身的消息循环的. Android通过Looper.Handler来实现消息循环机制,Andr ...
- Android HandlerThread 消息循环机制之源代码解析
关于 HandlerThread 这个类.可能有些人眼睛一瞟,手指放在键盘上,然后就是一阵狂敲.立即就能敲出一段段华丽的代码: HandlerThread handlerThread = new Ha ...
- Window Azure ServiceBus Messaging消息队列技术系列1-基本概念和架构
前段时间研究了Window Azure ServiceBus Messaging消息队列技术,搞了很多技术研究和代码验证,最近准备总结一下,分享给大家. 首先,Windows Azure提供了两种类型 ...
- 跟我一起学WCF(1)——MSMQ消息队列
一.引言 Windows Communication Foundation(WCF)是Microsoft为构建面向服务的应用程序而提供的统一编程模型,该服务模型提供了支持松散耦合和版本管理的序列化功能 ...
随机推荐
- scrapy-redis使redis不止保存url
先看scrapy-redis源码 class RedisMixin(object): """Mixin class to implement reading urls f ...
- Codeforces Round #550 (Div. 3)E. Median String
把字符串看作是26进制的数,从后往前翻译,那么就可以把两个串变成对应的26进制的数字,那么只要把两个数加起来除以二就得到中间的串对应的数了,同理再转化回来就行了.但是这样会有一个问题就是串的长度有2e ...
- HTTP 下载文件中文文件名在 Firefox 下乱码问题
转自:http://www.imhdr.com/991/ HTTP 下载文件,中文文件名在 Firefox 下乱码问题 最近帮助一同事解决 HTTP 下载文件时,中文文件名在 Firefox 下乱码的 ...
- [jzoj 5781]【NOIP提高A组模拟2018.8.8】秘密通道 (最短路)
传送门 Description 有一副nm的地图,有nm块地,每块是下列四种中的一种: 墙:用#表示,墙有4个面,分别是前面,后面,左面,右面. 起点:用C表示,为主角的起点,是一片空地. 终点:用F ...
- 16._source元数据
- http://www.phplo.com/special/2013/0616/467.html
http://www.phplo.com/special/2013/0616/467.html
- NET 爬虫
最近经常听说或者接触关于网络爬虫的问题,只是一直看到被人写的代码.而没有真正的做过实践, 昨天做了一下尝试,其中采用网络流行的扩展类库 http://html-agility-pack.net/?z= ...
- 《团队名称》第八次团队作业:Alpha冲刺
项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 代码敲不队 作业学习目标 (1)掌握软件测试基础技术(2)学习迭代式增量软件开发过程(Scrum) ...
- 优化 RequireJS 项目(合并与压缩) 【已翻译100%】
英文原文:Optimize (Concatenate and Minify) RequireJS Projects 标签: RequireJS Node.js 参与翻译 (1人) : 裴宝亮 本文将演 ...
- Sperner定理及其证明
额,最近看到了一个十分有趣的定理--Sperner定理.其实这个定理在OI中没什么用处,因此我都没把这篇文章放到我的OI标签里(不知道在MO中是否有用?)但是觉得它很有趣于是就过来写一下. 由于博主太 ...