Android的消息机制
一、简介
①、我们不能在子线程中去访问UI空控件,这是时候只能通过Handler将更新UI的操作放到主线程中去执行
②、Handler的组成:messageQueue和Looper的支持
③、MessageQueue:作用:存储了一组消息,以队列的形式对外提供插入和删除的工作。实际上是运用单链表的数据结构来存储消息列表的。
④、Looper 作用:由于MesageQueue无法处理消息,Looper填补了这一个功能,Looper会无限循环的形式去查找是否有新消息,如果有就处理消息,没有的话就一直等待
⑤、Looper的特殊概念ThreadLocal:并不是线程,但是可以在线程中存储数据。
举例:当Handler创建的时候默认会采用当前线程的Looper来构造其循环系统。那么如何获取当前线程的Looper,或者指定线程的Looper呢?
这就要使用到ThreadLocal,ThreadLocal能够在不同线程中互不干扰地存储和提取数据。所以通过ThreadLocal能够轻松获取每个线程的Looper。
注意:线程是默认没有Looper的,需要使用Handler就必须先为线程创建Handler
class LooperThread extends Thread {
public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } };
Looper.loop();
}
}
线程中创建Looper
为什么主线程就不需要呢?
因为在ActivityThread被创建是就已经初始化了Looper
二、消息机制概述
Android的消息机制:主要指Handler的运行机制和Handler所附带了MessageQueue和Looper的工作过程。
Handler的主要作用:讲一个任务切换到某个指定的线程中去执行,
问:Android为什么要有这个功能呢?
Android规定访问UI只能在主线程中执行:
在ViewRootImpl中对UI验证做了判断(P373 ①)。
如果没有Handler,我们在子线程中进行一些数据处理,之后要根据数据修改UI,如果没有Handler我们就无法将访问UI的工作切换到主线程中去。
问:为什么规定UI只能在主线程中执行?
因为如果多线程中并发访问可能会导致UI控件处于不可预期状态。
Handler的运行机制
1.当Handler创建完毕,说明其内部的Looper和MessageQueue可以和Handler协同工作了
2.通过Handler.post()方法将一个Runnable投递到Handler内部的Looper中去处理,或者使用send()方法。因为post()方法最终也是通过send方法来完成的。
3.send()方法的工作流程:当Handler的send()方法被调用时,它会调用MessageQueue的enqueueMessage()方法,将消息放入消息队列中,然后Looper发现有新消息来到的时候就会处理这条消息,最终消息中的Runnable()或者Handler的handler的handleMessage()方法就会被调用。
调用图:
三、Android的消息机制分析
ThreadLocal的工作原理
使用情景:当某些数据是以线程为作用域并且不同线程具有不同数据副本的时候。
举例:
private static final String TAG = "MainActivity";
private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();
//在mainThread中放入true类型的数据
mBooleanThreadLocal.set(true);
Log.d(TAG,"MainActivity"+mBooleanThreadLocal.get()); new Thread("Thread#1"){
public void run(){
mBooleanThreadLocal.set(false);
Log.d(TAG,"Thread#1"+mBooleanThreadLocal(.get());
}
} new Thread("Thread#2"){
publci void run(){
Log.d(TAG,"Thread#1"+mBooleanThreadLocal(.get());
}
}
MainActivity
返回结果:
MainActivity:true Thread#1:false Thread#2:null
说明:虽然不同线程访问的是同一个ThreadLocal但是根据线程不同,返回的数据是根据在对应线程中设置的数据。(就好像有副本一样)
工作原理:
1.查看ThreadLocal的set()方法(P377 ①)
①、首先获取当前线程
②、根据当前线程调用value()方法返回当前线程的value对象(其中存储了了该Thread的数据)。
Value类:Thread内部专门存储ThreadLocal的数据 (表示当前线程中存储了ThreadLocal的数据,而不是在ThreadLocal中存储了线程的数据)
③、将数据放入value.table这个数据结构中。
table数据结构:数组private Object[] table,ThreadLocal的值就存储在其中。
2.查看ThreadLocal的get()方法(P379 ①)
同样是取出当前线程的value.table()然后,根据索引获取数据
消息队列的工作原理(MessageQueue)
①、MessageQueue的操作
插入(enqueueMessage())和读取(next())(读取操作会伴随着删除操作)
②、enqueueMessage()的操作:简单的单链表的插入操作
next():寻找未被锁的Message,并返回给调用者,发现next()是一个无线循环的方法,如果存在Message则return跳出循环,不存在Message则进入阻塞
Looper的工作原理
作用:不同的调用MessageQueue的next()方法查看是否有新的信消息,如果有新的消息就会立即处理,如果没有就一直阻塞在那。
构造方法(P383 ①)
1.保存当前Thread对象。2.创建一个MessageQueue
线程中创建Looper:(P383 ②)
小提示:Looper提供了getMainLooper()方法,通过它可以在任何地方获取到主线程的Looper。
Looper的退出:
quit():直接退出Looper
quitSafely:是在消息队列中设定一个标记,当消息队列中的所有消息处理完毕之后才安全退出。
退出后,Handler的send()会返回false。
注:如果手动为子线程创建Looper,那么在所有的事情完成后,应该调用quit()方法终止消息循环,否则子线程会一直处于等待状态。如果退出Looper这个线程就会立刻终止。
分析Looper的loop()(P384 ①)
1、loop方法是一个死循环
2、再循环内通过调用MessageQueue.next();方法获取Message,如果next()中没有方法的时候,loop()方法会随next()方法一同阻塞。当next()方法返回null的时候,loop就会自动终止。
3、所以说调用Looper.quit(),就是调用MessageQueue.quit()或quitSafely()。
4、当获得msg之后,利用msg.target获取发送该msg的Handler,然后调用该handler的dispatchMessage(msg)方法。
Handler的工作原理
作用:发送消息和接收消息
主要方法:post一系列方法和send一系列方法,post一系列方法是通过send()一系列方法实现的;
分析send系列方法(P385 ①)
内部都是通过向MessageQueue添加一条msg
分析处理消息方法
1、首先检查msg对象的callback是否为null,callback就是Runnable对象(Handler.post()传递的Runnable对象)。不为null就交给handleCallback(msg)处理
2、其次检查mCallback是否为null,不为null,则调用mCallback的handleMessage()。
mCallback是一个接口,可以通过Callback创建Handler对象:Handler mHandler = new Handler(callback);
这样就可以在不用派生子类的情况下创建Handler。
3、最后调用Handler的handleMessage来处理消息
流程图:
Handler特殊的构造方法(P388 ①)
通过特定的Looper构造Handler
public Handler(Looper looper){
this(looper,null,false);
}
主线程的消息循环(P389 ①)
主线程的main()方法入口,通过Looper.parepareMainLooper()创建主线程的Looper和MessageQueue,通过Loop.loop()消息循环。之后通过ActivityThread.H这个Handler与消息队列交互。
AcitivtyThread通过ApplicationThread和AMS进行进程通信,AMS完成ActivityThread请求后会回调ApplicationThread的Binder方法,然后向Activity.H发送消息,将Binder线程池环境切换到主线程环境。
Android的消息机制的更多相关文章
- 《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制
第10章 Android的消息机制 10.1 Android消息机制概述 (1)Android的消息机制主要是指Handler的运行机制,其底层需要MessageQueue和Looper的支撑.Mes ...
- 【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什 ...
- 【原创】源码角度分析Android的消息机制系列(五)——Looper的工作原理
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. Looper在Android的消息机制中就是用来进行消息循环的.它会不停地循环,去MessageQueue中查看是否有新消息,如果有消息就立刻 ...
- 【原创】源码角度分析Android的消息机制系列(二)——ThreadLocal的工作过程
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 在上一篇文章中,我们已经提到了ThreadLocal,它并非线程,而是在线程中存储数据用的.数据存储以后,只能在指定的线程中获取到数据,对于其 ...
- Android 基础 十一 Android的消息机制
Handler是Android消息机制的上层接口,这使得在开发应用过程中我们只需要和Handler交互即可.Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去 ...
- Android的消息机制简单总结
参考文章: http://gityuan.com/2015/12/26/handler-message-framework/#next 参考资料: Android Framework的源码: Mess ...
- 聊一聊Android的消息机制
聊一聊Android的消息机制 侯 亮 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和消息机制,前者用于跨进程通信,后者用于进程内部通信. 从技术实现上来说,消息机制还是比 ...
- Android开发——Android的消息机制详解
)子线程默认是没有Looper的,Handler创建前,必须手动创建,否则会报错.通过Looper.prepare()即可为当前线程创建一个Looper,并通过Looper.loop()来开启消息循环 ...
- Android之消息机制Handler,Looper,Message解析
PS:由于感冒原因,本篇写的有点没有主干,大家凑合看吧.. 学习内容: 1.MessageQueue,Looper,MessageQueue的作用. 2.子线程向主线程中发送消息 3.主线程向子线程中 ...
随机推荐
- bootstrap模态框垂直居中
很久没有写东西了,之前想写一些移动端的东西以后补上吧,移动端发展还是蛮快的,回正题. 因为最近在弄一个系统,系统中引用了bootstrap,发现模态框垂直不居中,遂搜索了一下,也都试了一下,无非都是在 ...
- PHP中__autoload()的不解之处,求高手指点
一整段代码: 运行结果: 使用__autoload(),分为两页代码: 第一段代码: ACMEManager.php,代码如下: 运行结果:
- nginx+keepalived+tomcat之具体配置档
前沿知识点: nginx负责负载均衡(反向代理) msm(memcached session manager)负责缓存会话信息,从而实现会话保持 所需包: nginx和memcached采用最新稳定版 ...
- python bottle 框架开发任务管理系统 V_1.0版
经过1-2个星期的开发,现在开发了个半成品(UI现在比较烂,因为我的前端本来就很差,将就下吧),大概功能如下:用户功能(添加.删除.修改),添加部门功能,任务管理功能(添加.删除.修改,详细).项目管 ...
- mysql-protocol中对编码长度整数型的规则
固定长度整型数值在mysql 协议中的应用之一就是affected row :这个要根据首字节来判断 1.如果首字节小于251;那么首字节就是它要表示的数值. 2.如果首字节等于251;那么它表示的就 ...
- ckeditor详解
源网页编辑软件FCKEditor在09年发布更新到3.0,并改名为CKEditor.改进后的ckeditor更加模块话,配置更加灵活,和以前的fckeditor使用方式上也有所不同.在我的mvc项目中 ...
- Apache监控
Apache性能监控 http://www.cnblogs.com/fnng/archive/2012/11/11/2765463.html 要监控apache的性能,我们需要修改配置文件,允许查看a ...
- Qt Project的持续集成方案
作者:齐亮链接:http://www.zhihu.com/question/24314354/answer/27547787来源:知乎著作权归作者所有,转载请联系作者获得授权. PETER HARTM ...
- DOS命令行 定时关机&取消定时关机
命令行关机命令----shutdown Windows XP的关机是由Shutdown.exe程序来控制的,位于Windows\System32文件夹中. 如果你输入"shutd ...
- 查看mysql 服务器上的连接进程
SHOW PROCESSLIST #展示全部的连接进程 select * from information_schema.processlist where db='qwuliu' #可以进行筛选查 ...