Handler消息源代码分析
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
首先到Handler运行过程的总结:
1、 Looper.prepare()方法
为当前线程绑定looper。
在looper构造方法中创建一个messageQueue
2、 创建handler 重并写handleMessage方法
3、 使用handler发送消息,终于消息都会发送至messageQueue对象中。在messageQueue其中,全部的message按应该运行的时间的先后顺序,从小到大排列
4、Looper.loop()
在此方法中。开启死循环,不断的从messageQueue中取出应该运行的message,并运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法
參照以上分析在子线程中创建Handler对象:
new Thread(){
@Override
public void run() {
Message msg = Message.obtain();
Looper.prepare();//若没有调用此方法则抛出异常 Can't create handler inside thread that has not called Looper.prepare()
Handler handler2 = new Handler(){
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "收到子线程message消息", 0).show();
};
};
handler2.sendMessage(msg);
Looper.loop();
}
}.start();
对照在主线程中创建Handler实例对象我们发现,在子线程中创建Handler对象须要在创建前调用Looper.prepare()方法在创建后调用Looper.loop方法,那到底这两个方法是做什么的呢?
先看看系统的Looper.prepare方法:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 为当前线程绑定一个looper对象,以sThreadLocal为key
sThreadLocal.set(new Looper());
}
即:调用Looper.prepare方法时为当前线程绑定了一个Looper对象,所以Looper.prepare方法仅仅能调用一次。即一个线程仅仅能有一个Looper对象
再看看Looper的构造方法:
private Looper() {
mQueue = new MessageQueue();
}
由于一个线程仅仅能有一个Looper对象,所以一个线程也仅仅能有一个MessageQueue对象
先让我们看看Handler的构造方法:
public Handler() {
//获得当前线程的looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 获得looper中MessageQueue的引用
mQueue = mLooper.mQueue;
}
再看看系统的Looper.myLooper方法:即获取调用Looper.prepare方法时保存在sThreadLoad的Looper对象,所以Looper.prepare方法要在new Handler方法前调用
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
即:当创建Handler时会先调用Looper.myLooper()方法获取当前线程的Looper对象,假设Looper==null,则抛出异常
通过以上两个方法,当前线程的唯一Looper对象和MessageQueue对象都已创建,接下来该sendMessage了
查看系统源代码可知:sendEmptyMessage等。发送信息的方法,终于都是调用了SendMessageAtTime(msg,when);
而SendMessageAtTime(msg,when);方法终于的目的就是为了queue.enqueueMessage(msg, uptimeMillis);。当中msg为发送的Message对象,uptimeMillis为SystemClock.uptimeMillis() + when
查看系统的enqueueMessage方法,该方法终于实如今messageQueue其中。全部的message按运行的先后顺序,从小到大排列
final boolean enqueueMessage(Message msg, long when) {
msg.when = when; // 将运行时间设置给msg.when
Message p = mMessages; // 定义变量p = mMessage ,mMessage初终指向对列的第一个Message 对象
if (p == null || when == 0 || when < p.when) {
// 当队列中为空的时候,mMessage = msg
msg.next = p;
mMessages = msg;
this.notify();
} else {
// 否则将要进入队列的msg的运行时间和队列中的message的运行时间进行比較,
// 终于会使messageQueue中的全部的message按时间为顺序从小到大排列
// 即按运行的先后顺序排列
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
消息发送成功这时候该调用Looper.loop方法:即完毕了从MessageQueue中取出须要运行的Message。并运行我们重写的handlMessage方法
public static final void loop() {
//获得当前线程的looper对象及messageQueue对象
Looper me = myLooper();
MessageQueue queue = me.mQueue;
//开启while(true)循环
while (true) {
//从消息队列中取出一个message,假设message运行时间不到。那就wait等一会
Message msg = queue.next(); // might block
//运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法
msg.target.dispatchMessage(msg);
}
}
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
Handler消息源代码分析的更多相关文章
- Memcached源代码分析 - Memcached源代码分析之消息回应(3)
文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...
- handler 源代码分析
handler Looper 轮询器 MessageQueue 消息对象 1 主线程在一创建的时候就会调用, public static void prepareMainLooper() {}构造方法 ...
- RTMPdump(libRTMP) 源代码分析 10: 处理各种消息(Message)
===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...
- RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)
===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...
- RTMPdump(libRTMP) 源代码分析 8: 发送消息(Message)
===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...
- hostapd源代码分析(二):hostapd的工作机制
[转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...
- Hadoop源代码分析
http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...
- Android系统默认Home应用程序(Launcher)的启动过程源代码分析
在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...
- Android应用程序进程启动过程的源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...
随机推荐
- VSTO 学习笔记(十一)开发Excel 2010 64位自定义公式
原文:VSTO 学习笔记(十一)开发Excel 2010 64位自定义公式 Excel包含很多公式,如数学.日期.文本.逻辑等公式,非常方便,可以灵活快捷的对数据进行处理,达到我们想要的效果.Exce ...
- Codeforces 196 C. Paint Tree
分治.选最左上的点分给根.剩下的极角排序后递归 C. Paint Tree time limit per test 2 seconds memory limit per test 256 megaby ...
- 恶补jquery(四)jquery中事件--冒泡
事件 当我们在打开一个页面的时候.浏览器会对页面进行解释运行,这实际上是通过运行事件来驱动的.在页面载入事件时,运行Load()事件,是这个事件实现浏览器解释运行代码的过程. 事件机制 事件中的冒泡现 ...
- hdu3001(状压dp)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2 ...
- PSD 学位涵义 Poor, Smart and Deep desire to become rich 的缩写,不是真正的学位认证,是对一种心理状态的形容,所谓PSD学位是形容那些贫穷,但是很聪明,很深…_●.×
PSD 学位涵义 Poor, Smart and Deep desire to become rich 的缩写,不是真正的学位认证,是对一种心理状态的形容,所谓PSD学位是形容那些贫穷,但是很聪明,很 ...
- 怎样用Google APIs和Google的应用系统进行集成(1)----Google APIs简介
Google的应用系统提供了非常多的应用,比方 Google广告.Google 任务,Google 日历.Google blogger,Google Plus,Google 地图等等非常的多的应用,请 ...
- 我和小美的撸码日记(3)之中的一个句话搞定MVC表单页数据绑定与提交
另外献上在<线体验Demo地址>希望大家也能从中得到一些启示. 地址:http://121.40.148.178:8080/ . username:guest,password:12345 ...
- python学习1(小白记录)
python创建cocos2d-x项目注意点1. 2.7.5版本号的.配置好环境变量之后.要切换到tools文件夹下.直接运行 python create_project.py ..........这 ...
- 重温delphi之控制台程序:Hello World!
原文:重温delphi之控制台程序:Hello World! 这二天用c#开发ActiveX时,发现不管怎么弄,c#就是没办法生成ocx的纯正activeX控件,而且还要强迫用户安装巨大的.net f ...
- tab功能菜单——使用tab之间不同的交换机div
需求:在web实现类型的接口tab标签效应 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvem91eXVqaWUxMTI3/font/5a6L5L2T/fo ...