Android事件处理的两种模型

UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理。

对于基于监听器的事件处理而言,主要就是为Android界面组件绑定特定的事件监听器;对于基于回调的事件处理而言,主要做法是重写Android组件特定的回调函数,Android大部分界面组件都提供了事件响应的回调函数,我们主要重写它们就行。

一基于监听器的事件处理

相比于基于回调的事件处理,这是更具“面向对象”性质的事件处理方式。在监听器模型中,主要涉及三类对象:

1)事件源EventSource:产生事件的来源,通常是各种组件,如按钮,窗口等。

2)事件Event:事件封装了界面组件上发生的特定事件的具体信息,如果监听器需要获取界面组件上所发生事件的相关信息,一般通过事件Event对象来传递。

3)事件监听器EventListener:负责监听事件源发生的事件,并对不同的事件做相应的处理。

基于监听器的事件处理机制是一种委派式Delegation的事件处理方式,事件源将整个事件委托给事件监听器,由监听器对事件进行响应处理。这种处理方式将事件源和事件监听器分离,有利于提供程序的可维护性。

举例:

View类中的OnLongClickListener监听器定义如下:(不需要传递事件

public interface OnLongClickListener { boolean onLongClick(View v); }

View类中的OnLongClickListener监听器定义如下:(需要传递事件MotionEvent

public interface OnTouchListener { boolean onTouch(View v, MotionEvent event); }

二基于回调的事件处理

相比基于监听器的事件处理模型,基于回调的事件处理模型要简单些,该模型中,事件源和事件监听器是合一的,也就是说没有独立的事件监听器存在。当用户在GUI组件上触发某事件时,由该组件自身特定的函数负责处理该事件。通常通过重写Override组件类的事件处理函数实现事件的处理。

举例:

View类实现了KeyEvent.Callback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。

public interface Callback { // 几乎所有基于回调的事件处理函数都会返回一个boolean类型值,该返回值用于 // 标识该处理函数是否能完全处理该事件 // 返回true,表明该函数已完全处理该事件,该事件不会传播出去 // 返回false,表明该函数未完全处理该事件,该事件会传播出去 boolean onKeyDown(int keyCode, KeyEvent event); boolean onKeyLongPress(int keyCode, KeyEvent event); boolean onKeyUp(int keyCode, KeyEvent event); boolean onKeyMultiple(int keyCode, int count, KeyEvent event); }

三比对

基于监听器的事件模型符合单一职责原则,事件源和事件监听器分开实现;

Android的事件处理机制保证基于监听器的事件处理会优先于基于回调的事件处理被触发;

某些特定情况下,基于回调的事件处理机制会更好的提高程序的内聚性。

四基于自定义监听器的事件处理流程

在实际项目开发中,我们经常需要自定义监听器来实现自定义业务流程的处理,而且一般都不是基于GUI界面作为事件源的。这里以常见的app自动更新为例进行说明,在自动更新过程中,会存在两个状态:下载中和下载完成,而我们的程序需要在这两个状态做不同的事情,“下载中”需要在UI界面上实时显示软件包下载的进度,“下载完成”后,取消进度条的显示。这里进行一个模拟,重点在说明自定义监听器的事件处理流程。

4.1)定义事件监听器如下:

public interface DownloadListener { public void onDownloading(int progress); //下载过程中的处理函数 public void onDownloaded(); //下载完成的处理函数 }

4.2)实现下载操作的工具类代码如下:

public class DownloadUtils { private static DownloadUtils instance = null; private DownloadUtils() { } public static synchronized DownloadUtils instance() { if (instance == null) { instance = new DownloadUtils(); } return instance; } private boolean isDownloading = true; private int progress = 0; // 实际开发中这个函数需要传入url作为参数,以获取服务器端的安装包位置 public void download(DownloadListener listener) throws InterruptedException { while (isDownloading) { listener.onDownloading(progress); // 下载过程的简单模拟 Thread.sleep(1000); progress += 10; if (progress >= 100) { isDownloading = false; } } // 下载完成 listener.onDownloaded(); } }

4.3)最后在main函数中模拟事件源:

public class DownloadUI { public static void main(String[] args) { try { DownloadUtils.instance().download(new MyDownloadListener()); } catch (InterruptedException e) { e.printStackTrace(); } } private static class MyDownloadListener implements DownloadListener { @Override public void onDownloading(int progress) { System.out.println("下载进度是:" + progress); } @Override public void onDownloaded() { System.out.println("下载完成"); } } }

运行上面的模拟程序,输出如下所示:



五参考文献

1)《疯狂Android讲义》



你可能感兴趣的:(Android事件处理的两种模型)