Android事件处理
Android有两套事件处理机制:
1. 基于监听的事件处理
2. 基于回调的事件处理
一、 基于监听的事件处理
是一种基于委托式(Delegation)的事件处理方式。
1、 内部类的形式
2、 匿名类的形式
3、 直接绑定到标签
4、 外部类的形式
5、 Activity本身作为事件监听器
其中前三种较为好用,后两种不常用。
1、2大家都很熟悉了。
3举个例子:在Button标签里写一行代码:android:onClick=”clickHandler”,在该布局对应的Activity里定义一个void clickHandler(View source)方法即可。
4使用外部类的话,有两个缺点:
1、 事件监听器通常属于特定的GUI界面,定义成外部类不利于提高程序的内聚性。
2、 外部类形式的事件监听器不能自由访问创建GUI界面的类中的组件,编程不够简洁。此时需要在此外部类的方法里传递Activity、View作为参数才行。
5的话:
1、 Activity的主要职责是完成界面初始化,但此时还有包含事件处理方法,有点混乱。
2、 如果Activity界面类还要实现监听器接口(implements OnClickListener),让人觉得有点怪异。
二、 基于回调的事件处理
对于基于回调的事件处理模型来说,事件源与事件监听器是统一的,或者说事件监听器完全消失了。当用户在GUI组件上激发某个事件是,组件自己特定的方法将会负责处理该事件。举个例子:
类文件:
public class MyButton extends Button { publicMyButton(Context context , AttributeSet set) { super(context, set); } @Override publicboolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); Log.v("-crazyit.org-","the onKeyDown in MyButton"); //返回true,表明该事件不会向外扩散 returntrue; }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <!--使用自定义View时应使用全限定类名 --> <org.crazyit.event.MyButton android:layout_width="match_parent" android:layout_height="wrap_content" android:text="单击我"/> </LinearLayout>
基于回调的事件传播:
Android系统最先触发的是该按键上绑定的事件监听器,接着触发该组件提供的事件回调方法,然后还会传播到该组件所在的Activity。
public class MyButton extends Button { publicMyButton(Context context , AttributeSet set) { super(context, set); } @Override publicboolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); Log.v("-MyButton-","the onKeyDown in MyButton"); //第二个触发 //返回false,表明并未完全处理该事件,该事件依然向外扩散 returnfalse; } }
public class MainActivity extends Activity { @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Buttonbn = (Button) findViewById(R.id.bn); //为bn绑定事件监听器 bn.setOnKeyListener(newOnKeyListener() { @Override publicboolean onKey(View source ,int keyCode, KeyEvent event) { //只处理按下键的事件 if(event.getAction() == KeyEvent.ACTION_DOWN) { Log.v("-Listener-","the onKeyDown in Listener"); } //返回false,表明该事件会向外传播 returntrue; // 第①个触发 } }); } //重写onKeyDown方法,该方法可监听它所包含的所有组件的按键被按下事件 @Override publicboolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); Log.v("-Activity-", "the onKeyDown in Activity"); //返回false,表明并未完全处理该事件,该事件依然向外扩散 returnfalse;//第三个触发 } }
三、 响应的系统设置的事件
可使用Configurationcfg = getResourses().getConfiguration();来获取系统的Configuration对象。
如果要使程序自动响应系统设置更改,需要重写Activity的onConfigurationChanged(Configuration neConfig)方法,该方法可用于监听系统设置的更改。
四、Handler消息传递机制
由于Android不允许在子线程中更新界面组件,如果想在子线程中更新界面组件,开发者需要借助于Handler对象来实现。
Handler类的主要作用有两个:
1、 在新启动的线程中发送消息。
2、 在主线程中获取、处理消息。
举个例子:
public class MainActivity extends Activity { //定义周期性显示的图片的ID int[]imageIds = new int[] { R.drawable.java, R.drawable.javaee, R.drawable.ajax, R.drawable.android, R.drawable.swift }; intcurrentImageId = 0; @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); finalImageView show = (ImageView) findViewById(R.id.show); finalHandler myHandler = new Handler() { @Override publicvoid handleMessage(Message msg) { //如果该消息是本程序所发送的 if(msg.what == 0x1233) { //动态地修改所显示的图片 show.setImageResource(imageIds[currentImageId++ %imageIds.length]); } } }; //定义一个计时器,让该计时器周期性地执行指定任务 newTimer().schedule(new TimerTask() { @Override publicvoid run() { //发送空消息 myHandler.sendEmptyMessage(0x1233); } },0, 1200); } }