Andorid事件处理
在Andorid中已经很完善的包装了关于事件处理的方式,主要有两套机制:
基于监听的事件处理基于回调的事件处理 对于Android基于回调的时间处理来说: 主要做法重写Andorid组件特定的回调方法。Android中已经为大部分界面控件提供了回调方法,调用就好。对于Android监听的事件处理而言,就是我们经常遇到的组件绑定的事件监听器。 这篇文章主要写基于回调的事件处理,监听机制在我的上一篇文章中已经介绍
我自己的看法:回调机制取消了事件监听器,事件源和事件监听器合并。当用户在GUI组件上激发某个事件时,组件自己特定的方法(我们写的)将会负责处理该事件。我们需要做的就是为组件提供或者重写特定的处理方法。(注意,Java是一门静态的语言,没办法动态的添加方法,在这种情况下我们只能重写事件处理方法)
Android为所有GUI提供了事件处理回调的方法,以View为例,该类包含如下方法:
boolean onKeyDown(int keyCode, KeyEvent event) boolean onKeyLongPress(int keyCode, KeyEvent event) boolean onKeyShortcut(int keyCode, KeyEvent event) boolean onKeyup(int keyCode, KeyEvent event) boolean onTouchEvent(int keyCode, KeyEvent event) boolean onTrackballEvent(MotionEvent, KeyEvent event)下面举一个简单的例子来实验下回调机制 首先是一个简单的xml布局文件,设置一个Button
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.administrator.itentlearn.MyButton android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New Button" android:id="@+id/button1" android:layout_gravity="center_horizontal" /> </LinearLayout>大家注意看当中的
<com.example.administrator.itentlearn.MyButton这是一个自定义View 接下来我们来看看这个MyButton的实现方法
import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.widget.Button; import android.widget.Toast; /** * Created by Administrator on 2017/3/9 0009. */ public class MyButton extends Button{ public MyButton(Context context, AttributeSet set){ super(context, set); } /** * 这里重写onKeyDown方法,该按钮会自己处理相应的事件 * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event){ super.onKeyDown(keyCode, event); Log.v("Tag","first界面的绑定监听器"); //返回true,表明事件不会向外扩散 return true; } }这里利用MyButton继承Button类,实现接口onKeyDown,在GUI组件被被触发的时候回自动调用onKeyDown方法,不需要去绑定。其中onKeyDown方法的返回类型是true表明当前时间我已经在当前方法(onKeyDown)中处理完毕,不会向外传播,外部即使是绑定了其他的监听器也收不到消息。
基于回调机制下的事件传播 几乎所有的回调事件处理方法都有一个boolean类型的返回值。这个返回值和上文当中的一样用来标记当前事件是否已经处理完毕。
true :表明当前方法已经完全处理该事件,并且当前事件并不会向外传播false:表明当前方法并未完全处理该事件,该事件会传播出去对于事件传播的状态来说,组件上说发生的事件不仅激发该组件上的回调方法,也是出发组件所在Activity的回调方法。
下面的代码大家注意看 首先是一个xml布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.administrator.itentlearn.MySecondButton android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New Button" android:id="@+id/button_second1" android:layout_gravity="center_horizontal" /> </LinearLayout>在对应的MySecondButton文件中实现了对应的回调处理方法
import android.content.Context; import android.inputmethodservice.Keyboard; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.widget.Button; /** * Created by Administrator on 2017/3/9 0009. */ public class MySecondButton extends Button { public MySecondButton(Context context, AttributeSet set){ super(context, set); } /** * 重写onKeyDown方法,记住返回FALSE * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event){ super.onKeyDown(keyCode, event); Log.v("Log","second界面的回调事件处理,返回FALSE"); // 返回FALSE表明该事件还未处理完,会向外扩散 return false; } }并且在main中野绑定了该组件对应的监听方法:
import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.Button; /** * Created by Administrator on 2016/7/31 0031. */ public class second extends AppCompatActivity { private Button bt1; @Override public void onCreate (Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.second); bt1 = (Button) findViewById(R.id.button_second1); bt1.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View view, int i, KeyEvent keyEvent) { // 只要处理按下的事件 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN){ Log.v("Log","界面二的绑定监听事件处理,返回FALSE"); } // 返回FALSE表明事件会向外传播 return false; } }); } @Override public boolean onKeyDown(int keyCode, KeyEvent event){ super.onKeyDown(keyCode, event); Log.v("Log","onKeyDown事件处理,返回FALSE"); return false; } }最终实现完成后的样子(markdown不会贴图用的数据流)
03-09 10:31:32.588 7587-7587/com.example.administrator.itentlearn V/Log: 界面二的绑定监听事件处理,返回FALSE 03-09 10:31:32.588 7587-7587/com.example.administrator.itentlearn V/Log: second界面的回调事件处理,返回FALSE 03-09 10:31:32.588 7587-7587/com.example.administrator.itentlearn V/Log: onKeyDown事件处理,返回FALSERUA!!! 大家可以看到Android最先触发的是按键上绑定的事件监听器,接着才是该组件提供的事件回调方法,最后才是传播到组件所在Activity。
所以好吧,我推荐使用监听的方式来写事件处理。
回调机制的缺点:
可能造成程序结构混乱,Activity主要的职责是完成界面的初始化工作,但又包含了事件处理器的方法,很乱。没有实现软件工程的精髓:高内聚,低耦合。