基于回调的事件处理——基于回调的事件传播
几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于标识该处理方法是否能完全处理该事件:
- 如果处理事件的回调方法返回true,表明该处理方法以完全处理该事件,该事件不会传播出去。
- 如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件会传播出去。
对于基于回调的事件传播而言,某组件上所发生的事件不仅激发该组件上的回调方法,也会触发该组件所在Activity的回调用法——只要事件能传播到该Activiy。
下面的一个程序示范了Android系统中的事件传播,该程序重写了Button类的onKeyDown(int keyCode,KeyEvent event)方法,而且重写了该Button所在Activity的onKeyDown(int keyCode,KeyEvent event)方法——而且程序没有阻止事件传播,因此程序可以看到事件从Button传播到Activity的情形。
下面是从Button派生而出的MyButton子类代码。
package com.example.studyevent; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MyButton extends Button { public MyButton(Context context,AttributeSet set) { super(context,set); // TODO Auto-generated constructor stub } @Override public boolean onKeyDown(int keyCode,KeyEvent event) { super.onKeyDown(keyCode, event); Log.v("-crazyit.org-","the onKeyDown is MyButton"); //返回false,表明并未完全处理该事件,该事件依然向外扩散 return false; } @Override public boolean onTouchEvent(MotionEvent event) { Toast.makeText(this.getContext(),"触发事件onTouchEvent", Toast.LENGTH_SHORT).show(); return false; } }
上面的MyButton子类重写了onKeyDown(int keyCode,KeyEvent event)方法,当用户在该按钮上按下某个键时将会触发该方法。但由于该方法返回了false,这就意味着该事件还会继续向外传播。
该程序也按前一个示例的方式使用该自定义组件,并在Activity中重写public boolean onKeyDown(int keyCode,KeyEvent event)方法,该方法也会在某个按键被按下时被回调。
看如下Activity类代码。
package com.example.studyevent; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.View; import android.view.View.OnKeyListener; import android.widget.Button; public class Propagation extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_propagation); Button bn=(Button)findViewById(R.id.bn); //为bn按钮绑定监听器 bn.setOnKeyListener(new OnKeyListener(){ @Override public boolean onKey(View v, int keyCode, KeyEvent event) { // TODO Auto-generated method stub //只处理按下键的事件 if(event.getAction()==KeyEvent.ACTION_DOWN) { Log.v("-Listener", "the onKeyDown in Listener"); } //返回false,表明该事件会向外传播 return false; //① }}); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.propagation, menu); return true; } //重写onKeyDown方法,该方法可监听它所包含的所有组件的按键被按下事件 @Override public boolean onKeyDown(int keyCode,KeyEvent event) { super.onKeyDown(keyCode, event); Log.v("-Activity-","the onKeyDown is Activity"); //返回false,表明并未完全处理该事件,该事件依然向外扩展 return false; } }
从上面的程序可以看出,粗体字代码重写了Activity的onKeyDown(int keyCode,KeyEvent event)方法,当该Activity包含的所有组件上按下某个键时,该方法都可能被触发——只要该组件没有完全处理该事件。
不仅如此,上面的程序还采用监听模式来处理该按钮上的按键被按下的事件。
运行上面的程序,先把焦点移动到程序界面的按钮上,然后按下模拟器右边的按键,将可以在DDMS的LogCat中看到如图所示的输出:
从上图我们可以看出,当该组件上发生某个按键被按下的事件时,Android系统最先触发的应该是该按键上绑定的事件监听器,接着才触发该组件提供的事件回调方法,然后还会传播到该组件所在的Activity——但如果我们让任何一个事件处理方法返回了true,那么该事件将不会继续向外传播。例如我们改写上面的Activity代码,将程序中①号代码改为return true,然后再运行该程序、把焦点定位到该按钮上之后单击某个按键,在DDMS的LogCat中将看到下图所示的输出。