Android的事件处理
3.1 Android提供了两套事件处理机制:基于监听的事件处理、基于回调的事件处理。
3.2 基于监听的事件处理
3.2.1 监听的处理模型 主要涉及三类对象:EventSource、Event、EventListener。
Android的事件处理机制是一种委派式(Delegation)事件处理方式:普通组件将整个事件处理委托给特定的对象(事件监听器),可以把所有可能的事件授权给不同的事件监听器来处理,也可以让一类事件都使用同一个事件监听器来处理。
事件监听类是一个特殊的类,必须实现某Listener接口。
3.2.2 事件和事件监听器 如果事件足够简单、事件里封装的信息有限,那就无需封装事件对象、将事件对象出入事件监听器。但对于键盘事件、触摸屏事件,程序需要获取事件发生的详细信息,Android会把事件信息封装成xxxEvent对象,并传给事件监听器。
(源码\03\3.2\plane) 增加触摸事件:
planeView.setOnTouchListener(new View.OnTouchListener(){
@Override public boolean onTouch (View v, MotionEvent event)
......
说明:planeView所使用的事件监听器类是内部类,使用内部类可以在当前类中复用该监听器类;因为监听器类是外部类的内部类,所以可以*访问外部类的所有界面组件。这也是内部类的两个优势。
3.2.4 外部类作为事件监听器类 这种形式比较少见,因为不利于提高程序的内聚性,不能*访问创建GUI界面的类中的组件。但如果某个监听器确实需要被多个GUI界面所共享,而且主要完成某种业务逻辑的实现,则可以考虑用外部类的形式定义事件监听器类。
(源码\03\3.2\SendSms)
3.2.5 Activity本身作为事件监听器, 形式简单,但因为Activity的主要职责应该是完成界面初始化工作,界面类需要实现事件监听处理,比较奇怪,容易引起混乱。
3.2.6 匿名内部类作为事件监听器类, 这种形式是目前使用最广泛的事件监听器形式,因为事件处理器的复用价值不大。
3.2.7 直接绑定到标签,直接在界面布局文件中为指定标签绑定事件处理方法。
3.3 基于回调的事件处理
3.3.1 回调机制 对于这种事件处理模型,事件源和事件监听器是统一的,没有事件监听器了。Android为所有GUI组件都提供了一些事件处理的回调方法。继承GUI组件类,并重写该类的事件处理方法。
3.3.2 基于回调的事件传播 几乎所有基于回调的事件处理方法都有一个Boolean类型的返回值,如果返回true,表明该方法已完全处理该事件,该事件不会传播出去;如果返回false,表明该方法并未完全处理该事件,该事件会传播出去,会触发该组件所在Activity的回调方法。
3.3.3 对比
基于监听的事件处理模型具有的优势:分工明确,事件源、事件监听由两个类分开实现,由更好的可维护性;基于监听的事件监听器会被优先触发。
基于回调的事件处理机制的优势:可以更好地提高程序的内聚性。
3.4 响应系统设置的事件
监听系统设置的更改,对系统设置的更改做出响应。如:判断屏幕方向、系统方向的方向导航设备。
3.4.1 Configuration类 专门用户描述设备上的配置信息,既包括用户特定的配置项,也包括系统的动态设备配置。
3.4.2 重写Activity的onConfigurationChanged方法,响应系统设置更改,这个方法是基于回调的事件处理方法。
3.5 Handler消息传递机制
Android的UI操作不是线程安全的,Android的规则是:只允许主线程(UI线程,第一次启动时创建的) 修改Activity里的UI组件。如果新启动的线程需要动态修改界面组件的属性值,需要借助于Handler的消息传递机制来实现。
3.5.1 Handler类的主要作用:在新启动的线程中发送消息,在主线程中获取、处理消息。主线程只能通过回调的方式来适时处理其它线程发生的消息。(源码\03\3.5\HandlerTest)
2.5.2 Handler、Looper、MessageQueue的工作原理: 一个线程只能有一个Looper对象,Looper负责管理MessageQueue,Looper对象会创建MessageQueue,MessageQueue采用先进先出的方式管理消息;主UI线程中,系统为其初始化了一个Looper对象,因此程序直接创建Handler即可;程序员启动的子线程,必须自己创建一个Looper对象,并调用它的prepare()方法和loop()方法启动它即可。(源码\03\3.5\CalPrime)
尽量避免在UI线程中执行耗时操作,因为这可能导致一个“著名”的 异常:ANR异常,应用无法响应输入事件和Broadcast。Android默认约定当UI线程阻塞超过20秒将会引发ANR异常。
3.6 异步任务 AsyncTask
AsyncTask 适用于简单的异步处理,是轻量级的,不需要借助线程和Handler即可实现。
AsyncTask<Params, Progress, Result> 是抽象类,它定义了如下三种泛型类型:Params是启动任务执行的输入参数,Progress是后台任务完成的进度值,Result是后台任务完成后的返回结果。
使用AsyncTask需要创建它的子类,并根据需要实现相关方法。
(源码\03\3.6\AsyncTaskTest)
使用AsyncTask时必须遵守的规则:必须在UI线程中创建它的实例;必须在UI线程中调用它的execute()方法;AsyncTask的onPreExecute()、onPostExecute()等方法只能由Android系统负责调用;每个AsyncTask只能被执行一次。