模型说明
在UI编程中,常常要对鼠标点击进行相应,首先如何获得鼠标点击呢?
方式一:创建一个线程,该线程一直循环检测是否有鼠标点击,那么这个方式有以下几个缺点:
1. CPU资源浪费,可能鼠标点击的频率非常小,但是扫描线程还是会一直循环检测,这会造成很多的CPU资源浪费;如果扫描鼠标点击的接口是阻塞的呢?
2. 如果是堵塞的,又会出现下面这样的问题,如果我们不但要扫描鼠标点击,还要扫描键盘是否按下,由于扫描鼠标时被堵塞了,那么可能永远不会去扫描键盘;
3. 如果一个循环需要扫描的设备非常多,这又会引来响应时间的问题;
所以,该方式是非常不好的。
方式二:就是事件驱动模型
目前大部分的UI编程都是事件驱动模型,如很多UI平台都会提供onClick()事件,这个事件就代表鼠标按下事件。事件驱动模型大体思路如下:
1. 有一个事件(消息)队列;
2. 鼠标按下时,往这个队列中增加一个点击事件(消息);
3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
4. 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;
如图:
Android的Looper和Handler模型
在Android系统中,一般的事件驱动应用都可以使用Looper和Handler来实现,uml如下
UML
说明
Message是一个个的消息,每个消息代表一个事件,每个Message都有独立的处理者target;
多个消息利用Message里的next属性首尾相接组成一个MessageQueue队列;
MessageQueue提供了插入Message接口enqueueMessage和读取Message接口next;
Looper是一个循环类,它利用MessageQueue的next接口,不断从MessageQueue获得消息;
如果Looper获得了一个消息Message,那么就调用Message的target来处理该消息,这个target其实就是一个Handler;
Handler的HandlerMessage函数就是处理Message的地方,这是一个接口函数,所以使用者根据业务需求重写这个接口;
Handler除了处理Message外,还提供了插入Message的接口sendMessage,从这也可以看出,利用这四个类设计最简单的事件驱动模型只需操作Hanlder一个类即可,因为它既提供了插入消息的接口,也提供了处理消息的接口;
当然这四个类除了MessageQueue之外,其他三个用户都可以根据业务需求操作实现更复杂的模型,我们可以自己创建一个Message而不是使用Message的默认创建方法(如可以为每个Message设计不同的处理函数,不一定使用HandlerMessage),然后通过Handler插入到消息队列中;然后创建自己的Looper线程,自己独自使用一个Looper;之所以MessageQueue不能自行设计,是因为Android的设计问题,因为MessageQueue是在Looper的构造函数自己new的。
重点代码分析
Handler的handleMessage优先级
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- /**
- * Handle system messages here.
- */
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
looper读取一个消息后,首先执行的是dispatchMessage,然后dispatchMessage根据不同条件调用不同的handleMessage;
这里边有好多callback,是因为不一定非要使用Handler提供的handleMessage接口处理消息,也可以有很多其他方式设置回调函数;
优先级最高的是msg.callback,如果要处理的Message本身有处理回调接口,那么就使用Message本身的;
优先级次之的是mCallback,mCallback是在Handler的构造函数设置的,说明可以为Handler统一设置一个处理回调接口;
优先级最低的是handleMessage,这个才是handleMessage用户重写的接口;
设置这些优先级,主要为了在应用中需要处理的消息有很多种分类,但是它们共用一个Looper,如
1. 如果所有的消息属于一个分类,那么只需要一个Handler即一个handleMessage即可;
2. 如果消息分属于不同的分类,那么每个分类使用一个Handler管理,即每个分类使用一个handleMessage,即mCallback;
3. 如果所有的消息种类都不一样,如果使用一个Handler在逻辑上不伦不类,所以,这个时候不如为每个消息设置一个回调函数更好,即msg.callback;
MessageQueue的时间优先级when
Handler是通过enqueueMessage接口将消息插入到MessageQueue的,在插入的时候就已经将消息按照时间排序了,其中时间0代表最高的优先级,时间越大,优先级越小,越延后处理
所以,Looper通过MessageQueue的next接口获得的消息就是优先级最高的消息,next不需要重新排序消息队列了;
HandlerThread的作用
如果我们需要自己创建Looper,需要将创建的Looper和创建的Handler联系在一起。如果两个对象的创建是在一个线程里,并且先创建Looper后创建Handler是没有问题的;但是如果两个对象是在两个线程里创建,有可能在构造Handler时,Looper并没有真正的创建好,其实这之间只要通过一个同步就可以。HandlerThread就是Android提供给我们用的一个类,它已经做好了同步,所以可以安全使用。
相关推荐
Simulink仿真模型-逆变驱动(SPWM驱动)
医疗设备软件开发-模型驱动.pdf
1、传统的编程模式 2、事件驱动模型 3、第三种就是协程、事件驱动的方式,一般普遍认为第(3)种方式是大多数网络服务器采用的方式 1、创建一个线程循环检测是否有
SpringBoot整合RabbitMQ之Spring事件驱动模型-系统源码数据库流程图 SpringBoot整合RabbitMQ实战视频教程:https://edu.csdn.net/course/detail/9314 (感兴趣也可以加QQ联系:1974544863)
事件驱动模型实例详解(Java篇)
MDA白皮书-模型驱动开发和UML 2.0
Java 开发中事件驱动模型的实例详解,属于转的
模型驱动工程(MDE)专注于创建软件模型并自动从模型生成代码。 模型驱动软件开发(MDSD)提供了更为有效的方法。 这些方法改善了构建软件的方式。 模型驱动的方法部分提高了开发人员的生产力,降低了软件构建的...
论文研究-基于驱动控制的多变量离散灰色模型.pdf, 针对多变量灰色模型存在驱动项作用机制不明确和模型精度不高的问题,通过引入矩形函数控制驱动项,构造一种新的多变量...
u-boot中的i2c驱动模型----visionfive开发板
windows驱动程序模型设计-光盘1和2
领域模型使开发人员可以表达丰富的软件功能需求,由此实现的软件可以满足用户真正的需要,因此被公认为是软件设计的关键所在,其重要性显而易见。但讲述如何将领域模型用于软件开发过程的优秀实用资料却不多见。本书...
microsoft windows驱动程序模型设计2nd-随书光盘2
领域驱动设计入门以及实践,如何用领域驱动设计来做
Linux驱动程序开发-设备驱动模型 Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。
模型驱动软件设计课件(UML),全面完整,其中还有一些MDA的知识,对朋友们有很好的帮助。
1、传统的编程模式例如:线性模式大致流程开始--->代码块A--->代码块B--->代码块C--->代码块D--->......--->...例如:事件驱动型程序模型大致流程开始--->初始化--->等待与
MDA简介、MDA开发过程、 简单的MDA框架 、MDA应用案例、 完整的MDA框架、 OMG相关标准、模型变换
领域驱动设计(Domain-Driven Design,DDD)是Evans提出来的用来处理软件系统核心复杂性的方法。该方法的有效性在实践中得到证明,但是方法在细节上存在不够清晰、对设计人员素质要求高等问题。在对大量业务系统进行...
本子原内容在分析数字孪生基本概念的基础上,以智能制造和智能建造为基本切入点,阐述模型驱动方法和数据驱动智能的融合技术,为数字孪生的构建、设计和实现提供了技术指引。同时,结合典型软件平台,给出数字孪生...