Android提供了另外一种事件处理模型,那就是基于回调的事件处理模型。从代码的角度而言,基于回调的事件处理模型,更多应用是为了扩展原有组件,在原有组件的基础之上扩展功能。下面来详细介绍基于回调的事件处理。
就基于监听器的事件模型的几个组成部分来区分,基于回调的事件处理模型的事件源和事件监听器是同一个,可以理解为没有明确的事件监听器,事件源对自己进行自监听。当用户在这个组件上激发了某个事件之后,组件自己会负责对该事件的处理方法进行回调。
使用回调机制来处理事件非常的简单,只需要继承特定的组件类,并且重写该类的特定的事件处理方法即可。
示例:继承一个Button,并重写其中的onTouchEvent事件。
代码清单:\codes\04\03\CallbackEventDemo\src\com\bookdemo\callbackeventdemo\TouchButton.java
public class TouchButton extends Button { private Context context; public TouchButton(Context context , AttributeSet set) { super(context,set); this.context = context; } @Override public boolean onTouchEvent(MotionEvent event) { // 重写Button上的触摸事件 if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.i("main", "TouchButton响应了OnTouch事件"); Toast.makeText(context, "您触摸了按钮", Toast.LENGTH_SHORT).show(); } return false; } }
这里定义了一个Button的子类,并且实现了onTouchEvent事件,这是一个触摸事件。
代码清单:\codes\04\03\CallbackEventDemo\res\layout\activity_base.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.bookdemo.callbackeventdemo.TouchButton android:id="@+id/touchButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TouchButton" /> </LinearLayout>
在XML布局文件中使用定义好的TouchButton,在Android中使用自定义的组件,需要使用组件的全限定类名。
接下来只需要定义一个Activity映射这个布局资源文件即可,无需为TouchButton额外声明触摸事件的响应,因为这个TouchButton按钮会自己处理触摸事件。
在模拟器上运行效果如下:
Android的界面设计风格外层容器包裹内层组件,很多层层包裹的容器或组件具有相同的回调事件,在触发这个事件的时候,将由哪个组件来完成对事件的响应呢?Android的基于回调的事件模型也考虑过这个问题,和大多数其它平台的设计理念一样,有一个事件传播的概念。
在Android下,大多数基于回调的事件处理方法都有一个boolean类型的返回值,这个返回值表示了该处理方法是否已经处理完该事件,从而判断该事件是否还需要向外层组件传播。规则如下:
· 如果事件处理的回调方法返回的是true,表示该组件的处理方法已经完全处理此事件,无需将事件向外传播。
· 如果事件处理的回调方法返回的是false,表示该组件虽已处理过此事件的响应,但是没有完全处理,还需要向外传播,看是否有外层组件需要处理此事件,直到有某个外层组件返回true结束此事件的传播或者传播到最外层为止。
示例:基于前面定义的TouchButton,继续重写一个Activity,并为TouchButton注册触摸事件的事件监听器,并且为Activity事件触摸事件的回调方法,查看其传播顺序。在此实例中会使用到简单的Log日志。
代码清单:\codes\04\03\CallbackEventDemo\src\com\bookdemo\callbackeventdemo\CallbackEventCastActivity.java
public class CallbackEventCastActivity extends Activity { private TouchButton touchButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); touchButton=(TouchButton) findViewById(R.id.touchButton); touchButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.i("main", "TouchButton的基于事件监听器监听的OnTouch被触发"); } return false; } }); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.i("main", "Activity响应OnTouch事件"); } return super.onTouchEvent(event); } }
在模拟器上运行,在LogCat中查看日志输出:
在这个实例中,对TouchButton的onTouch事件实现了三次响应方法,分别是TouchButton本身的基于回调的事件响应、TouchButton基于事件监听器的事件响应、Activity响应onTouch事件,TouchButton本身的两个onTouch事件的响应方法返回的均是false,所以可以向外传播。从日志中可以看出,onTouch事件的传播顺序,并且可以看出,基于监听器的事件要先于基于回调的事件被处理。如果不想onTouch事件继续传播,只需要在事件响应方法中返回false,即可终止onTouch事件的传播。
详细介绍完Android提供的两种事件处理机制,不难发现基于监听器的事件处理模型具有更大的优势,基于监听器的事件模型分工更明确,事件源、事件监听器由两个对象分别表示,清晰明了,维护性更强。而且Android的事件处理机制也会导致基于监听器的事件会优先于基于回调的事件被触发。