《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制
第10章 Android的消息机制
10.1 Android消息机制概述
(1)Android的消息机制主要是指Handler的运行机制,其底层需要MessageQueue和Looper的支撑。MessageQueue是以单链表的数据结构存储消息列表但是以队列的形式对外提供插入和删除消息操作的消息队列。MessageQueue只是消息的存储单元,而Looper则是以无限循环的形式去查找是否有新消息,如果有的话就去处理消息,否则就一直等待着。
(2)Handler的主要作用是将一个任务切换到某个指定的线程中去执行。
为什么要提供这个功能呢?
Android规定UI操作只能在主线程中进行,ViewRootImpl的checkThread方法会验证当前线程是否可以进行UI操作。
为什么不允许子线程访问UI呢?
这是因为UI组件不是线程安全的,如果在多线程中并发访问可能会导致UI组件处于不可预期的状态。另外,如果对UI组件的访问进行加锁机制的话又会降低UI访问的效率,所以还是采用单线程模型来处理UI事件。
(3)Handler的创建会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程中不存在Looper的话就会报错。Handler可以用post方法将一个Runnable投递到消息队列中,也可以用send方法发送一个消息投递到消息队列中,其实post最终还是调用了send方法。
10.2 Android的消息机制分析
(1)ThreadLocal的工作原理
1.ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。一般来说,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,可以考虑使用ThreadLocal。 对于Handler来说,它需要获取当前线程的Looper,而Looper的作用域就是线程并且不同线程具有不同的Looper,这个时候通过ThreadLocal就可以实现Looper在线程中的存取了。
2.ThreadLocal的原理:不同线程访问同一个ThreadLocal的get方法时,ThreadLocal内部会从各自的线程中取出一个数组,然后再从数组中根据当前ThreadLocal的索引去查找出对应的value值,不同线程中的数组是不同的,这就是为什么通过ThreadLocal可以在不同线程中维护一套数据的副本并且彼此互不干扰。
3.ThreadLocal是一个泛型类public class ThreadLocal<T>,下面是它的set方法
public void set(T value) {
|
Values是Thread类内部专门用来存储线程的ThreadLocal数据的,它内部有一个数组private Object[] table,ThreadLocal的值就存在这个table数组中。如果values的值为null,那么就需要对其进行初始化然后再将ThreadLocal的值进行存储。
ThreadLocal数据的存储规则:ThreadLocal的值在table数组中的存储位置总是ThreadLocal的索引+1的位置。
(2)MessageQueue的工作原理
1.MessageQueue其实是通过单链表来维护消息列表的,它包含两个主要操作enqueueMessage和next,前者是插入消息,后者是取出一条消息并移除。
2.next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里。当有新消息到来时,next方法会返回这条消息并将它从链表中移除。
(3)Looper的工作原理
1.为一个线程创建Looper的方法,代码如下所示
new Thread("test"){
|
2.Looper的prepareMainLooper方法主要是给主线程也就是ActivityThread创建Looper使用的,本质也是调用了prepare方法。
3.Looper的quit和quitSafely方法的区别是:前者会直接退出Looper,后者只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后才安全地退出。Looper退出之后,通过Handler发送的消息就会失败,这个时候Handler的send方法会返回false。
在子线程中,如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态,而如果退出Looper以后,这个线程就会立刻终止,因此建议不需要的时候终止Looper。
4.Looper的loop方法会调用MessageQueue的next方法来获取新消息,而next是一个阻塞操作,当没有消息时,next方法会一直阻塞着在那里,这也导致了loop方法一直阻塞在那里。如果MessageQueue的next方法返回了新消息,Looper就会处理这条消息:msg.target.dispatchMessage(msg),其中的msg.target就是发送这条消息的Handler对象。
(4)Handler的工作原理
1.Handler就是处理消息的发送和接收之后的处理;
2.Handler处理消息的过程
public void dispatchMessage(Message msg) {
|
3.Handler还有一个特殊的构造方法,它可以通过特定的Looper来创建Handler。
public Handler(Looper looper){
|
4.Android的主线程就是ActivityThread,主线程的入口方法就是main,其中调用了Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()方法来开启主线程的消息循环。主线程内有一个Handler,即ActivityThread.H,它定义了一组消息类型,主要包含了四大组件的启动和停止等过程,例如LAUNCH_ACTIVITY等。ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间通信的方法完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
OK,本章结束,谢谢阅读。
《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制的更多相关文章
- Android开发艺术探索读书笔记——01 Activity的生命周期
http://www.cnblogs.com/csonezp/p/5121142.html 新买了一本书,<Android开发艺术探索>.这本书算是一本进阶书籍,适合有一定安卓开发基础,做 ...
- Android开发艺术探索读书笔记——进程间通信
1. 多进程使用场景 1) 应用某些模块由于特殊需求须要执行在单独进程中. 如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会由于应用程序进程crash而受影响. 2) 为加大一个应用可 ...
- android开发艺术探索读书笔记之-------view的事件分发机制
View的点击事件的分发,其实就是对MotionEvent事件的分发过程,即当一个MotionEvent产生后,系统需要把这个事件传递给一个具体的View,而这个过程就是分发过程. 分发过程主要由以下 ...
- Android开发艺术探索学习笔记(十一)
第十一章 Android的线程和线程池 从用途上来说,线程分为子线程和主线程,主线程主要处理和界面相关的事情,而子线程往往用于执行耗时的操作.AsyncTask,IntentService,Hand ...
- Android开发艺术探索学习笔记(十)
第十章 Android的消息机制 面试中经常会被问到的一个问题:handler是如何在子线程和主线程中进行消息的传递的,这个问题通过了解Android的消息机制可以得到一个准确的答案. Androi ...
- Android开发艺术探索学习笔记(六)
第六章 Android的Drawable Drawable的优点:使用简单,比自定义view的成本要低:非图片类型的Drawable占用空间小,有利于减小APK安装包的大小. 6.1Drawable ...
- Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧
第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DP ...
- Android开发艺术探索学习笔记(三)
第三章 View的事件体系 3.1 View基础知识 3.1.1 什么是view View 是Android中所有控件的基类,是一种界面层的控件的一种抽象,它代表了一个控件. 3.1.2 View的 ...
- Android开发艺术探索学习笔记(四)
第四章 View的工作原理 4.1初识ViewRoot和DecorView ViewRoot是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成 ...
- Android开发艺术探索学习笔记(一)
第一章 Activity的生命周期和启动模式 1.1Activity的生命周期全面解析 1.1.1典型情况下的生命周期分析 (1)在两个Activity进行切换时,当前的Activity的onPaus ...
随机推荐
- ecshop--加载初始化文件
define('IN_ECS', true);require(dirname(__FILE__) . '/../../includes/init.php'); 在开头要加入这两句文件才可以访问数据库以 ...
- MySql数据库3【优化3】缓存设置的优化
1.表缓存 相关参数: table_open_cache 指定表缓存的大小.每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容.通过检查峰值时间的状 ...
- Why GEMM is at the heart of deep learning
Why GEMM is at the heart of deep learning I spend most of my time worrying about how to make deep le ...
- City Game
hdu1505:http://acm.hdu.edu.cn/showproblem.php?pid=1505 题解:给你一个字符矩阵,里面有R和F两种字符,然后让你找一个最大的子矩阵,这个最大的子矩阵 ...
- 源代码安装GIT
参考URL:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25150840&id=4250659 若是条件允许,从源代 ...
- find the most comfortable road
XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级空中漫游结构)进行交流,每条SARS都对行驶在上面的Flycar限制了固定的Spee ...
- 【转】android ListView详解---- 不错不错
原文网址:http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html 由于google doc 很多人都打不开,故更新了源码下载地址 [源 ...
- 图论(二分图最大权独立点集):COGS 2051. 王者之剑
2051. 王者之剑 ★★★☆ 输入文件:Excalibur.in 输出文件:Excalibur.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] 这是在阿尔托 ...
- 线性代数(矩阵乘法):POJ 2778 DNA Sequence
DNA Sequence Description It's well known that DNA Sequence is a sequence only contains A, C, T and ...
- 数学(GCD,计数原理)HDU 5656 CA Loves GCD
CA Loves GCD Accepts: 135 Submissions: 586 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 2621 ...