Android提供了两套事件处理机制,分别是:基于监听的事件处理机制和基于回调的事件处理机制。
基于监听的事件处理机制
事件监听机制由事件源、事件、事件监听器三类对象组成,基本处理流程如下:
为某个事件设置一个监听器,监听用户的操作
用户操作触发了事件源的监听器
生成事件对象
将这个事件源对象作为参数传递给事件监听器
事件监听器对事件进行判断,执行对应的事件处理方法
简单的说就是:事件监听机制是一种委派式的事件处理机制,事件源(就是我们的组件,比如Button)将事件处理委托给事件监听器,当事件源发生指定事件时,就通知指定事件监听器,执行相应的逻辑操作。
在Android中,有一下五种基于事件监听的处理形式:
1、匿名内部类作为事件监听器
这是我们最常用的一种方式,直接设置setXxxisntener,重写里面的方法即可,比如:
findViewById(R.id.btn_search_weather).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, WeatherActivity.class);
startActivity(intent);
}
});
这种方式比较简单,但是只能单次使用,不能复用
2、内部类作为事件监听器
这个与匿名内部类作为监听器不同,可以重复使用,也可以访问外部类的组件,使用也比较多,比如:
class ButtonClickListener implements View.OnClickListener{
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, WeatherActivity.class);
startActivity(intent);
}
}
3、外部类作为事件监听器
新建一个类实现相应的事件,这种方式使用比较少,不能访问Activity里面的组件,比如:
package com.example.webservicedemo;
import android.view.View;
/**
* Created by Devin on 2016/8/10.
*/
public class OnButtonClickListener implements View.OnClickListener {
private String content;
public OnButtonClickListener(String content) {
this.content = content;
}
@Override
public void onClick(View view) {
//执行操作
}
}
4、Activity本身作为事件监听器
直接让Activity实现XxxListener,然后重写里面的方法,组件设置监听为this即可,例如:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_search_phone).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PhoneActivity.class);
startActivity(intent);
}
});
findViewById(R.id.btn_search_weather).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, WeatherActivity.class);
startActivity(intent);
}
});
findViewById(R.id.btn_handler_ui).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
findViewById(R.id.btn_handler_son).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, SonHandlerActivity.class);
startActivity(intent);
}
});
findViewById(R.id.btn_search_weather).setOnClickListener(this);
}
//重写onClick方法
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, WeatherActivity.class);
startActivity(intent);
}
这种方法如果是多个组件同时使用这种监听方式的话需要判断点击的是哪一个组件
5、直接绑定到标签
这种就是直接在XML布局文件中给需要设置监听的组件设置一个android:onClick=”监听方法”属性,然后在相应的Activity中实现该方法。
基于回调的事件处理机制
所谓的回调,在实现具有通用性质的应用架构时非常常见:对于一个具有通用架构的程序来说,程序架构完成整个程序的通用功能、流程,但在某个特定的点上,需要一段业务相关的代码——通用的程序架构无法实现这段代码,那么程序架构会在这个点上留一个“空”。
有两种方式:
以接口形式存在:该接口由开发者实现,实现该接口时会实现该接口的方法,那么通用的程序架构就会调用该方法来完成相关业务的处理。
以抽象方法(也可以说是非抽象方法)的形式存在:这就是Activity的实现形式,这些特定的点上的方法已经被定义了,如onCreate,onActivityResult等方法,开发者可以选择性地重写这些方法,通用的程序架构就会回调这些方法来完成相关业务的处理。
举个简单的例子说明一下事件回调机制:
张三叫李四去统计公司周末有多少人去聚餐的,但是张三因为有事情需要处理,不能等到李四全部统计完,所以就跟李四做一个约定,统计完了打电话告诉张三。张三跟李四约定了一个接口,张三叫李四统计去聚餐的人数,当李四统计完之后通过这个接口告诉张三周末聚餐的人数,这个就是回调。
Android提供了以下回调方法:
onKeyDown (int keyCode, KeyEvent event):用于捕捉手机键盘被按下的事件,返回值是boolean类型,返回true测试自己消费这个事件,false测试不消费这个事件,让其它回调方法处理
onKeyUp (int keyCode, KeyEvent event):用于捕捉手机键盘松开事件,返回值也是boolean类型,true表示自己消费这个事件,false测试不消费。
onTouchEvent (MotionEvent event):处理手机屏幕触摸事件,返回值同样是boolean类型,true表示自己消费,false表示让其它回调方法处理,这个方法一般处理三个事件:屏幕按下MotionEvent.ACTION_DOWN、屏幕被抬起MotionEvent.ACTION_UP、在屏幕上滑动MotionEvent.ACTION_MOVE
onTrackballEvent (MotionEvent event):手机中轨迹球的回调,在所有的View中都有实现,返回值也是boolean类型,与前面介绍的回调方法返回值机制一样。
onFocusChanged (boolean gainFocus, int direction, Rect previously FocusedRect) :焦点改变的回调方法,此方法只能在View中实现,返回值类型是void。
与焦点有关的常用方法有:
setFocusable方法:设置View是否可以拥有焦点。
isFocusable方法:监测此View是否可以拥有焦点。
setNextFocusDownId方法:设置View的焦点向下移动后获得焦点View的ID。
hasFocus方法:返回了View的父控件是否获得了焦点。
requestFocus方法:尝试让此View获得焦点。
isFocusableTouchMode方法:设置View是否可以在触摸模式下获得焦点,在默认情况下是不可用获得的。
在Android中,使用到回调的一般有两种情况:自定义View和基于回调的传播机制。在自定义View中回调使用的比较多,下面我们通过一个例子实现一下:
package com.example.webservicedemo;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.Button;/**
- Created by Devin on 2016/8/10.
*/
public class AutoButton extends Button {
private static String TAG = “AutoButton”;
public AutoButton(Context context) {
super(context);
}public AutoButton(Context context, AttributeSet attrs) {
super(context, attrs);
}public AutoButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i(TAG,”——–>onKeyDown事件被触发”);
return true;
}@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.i(TAG,”——–>onKeyUp事件被触发”);
return true;
}@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG,”——–>onTouchEvent事件被触发”);
return true;
}
}- Created by Devin on 2016/8/10.
我们重写了Button的三个事件,点击按钮后触发onTouchEvent事件,当我们按模拟器上的键盘时, 按下触发onKeyDown,离开键盘时触发onKeyUp事件。当发生点击事件后就不需要我们在Java文件中进行 事件监听器的绑定就可以完成回调,即组件会处理对应的事件,即事件由事件源(组件)自身处理。
关于事件处理就简单介绍到这里,事件处理主要的核心是了解事件的传播顺序:监听器优先,接着是View本身,最后是Activity,返回值是boolean类型,true的话就是拦截事件传播,自己消费,false测试不拦截事件,让下一层的回调方法处理。