2012.8.26
一、事件相关概述
在图形界面(UI)的开发中,有两个非常重要的内容:一个是控件的布局,另一个就是控件的事件处理,其中,控件的布局已经在http://blog.sina.com.cn/u/2726952293中“Android UI基础知识”部分已经说明,本部分主要对事件的处理进行分析。Android应用程序中事件的处理秉承了JavaSE图形用户界面的处理方式和风格。
Android在事件处理过程中主要涉及到3个概念:
1)事件:表示用户在图形界面的操作的描述,通常是封装成各种类,比如:键盘事件操作相关的类为KeyEvent、触摸屏相关的移动事件类为MotionEvent等,在后面我们将专门列出相关的事件。
2)事件源:事件源是指事件发生的场所,通常是指各个控件,例如:Button、EditText等控件。
3)事件处理者:事件处理者是指接收事件对象并对其进行处理的对象,事件处理一般是一个实现某些特定接口类创建的对象。
二、事件处理模型
事件处理模型通常有三种方式:接口实现事件处理模型、内部类事件处理模型和匿名内部类事件处理模型三种。下面以响应Button事件源,单击事件以及弹出响应结果为例说明以上三种事件处理模型。
1、接口实现事件处理模型
以下Button按钮响应机制为:单击Button的时候,屏幕上的TextView中输出“你好!”。
通过DroidDraw设计的带Button按钮的布局,如图1所示:
图1 布局文件的设计
其中,布局代码如下:
android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> android:layout_width="165dp" android:layout_height="38dp" android:text="TextView" />
以下代码为在Activity中实现接口,并且绑定在Button按钮上:
package com.wjy.usersrc;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity extends Activity implements OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 以下是定义Button按钮 */
Button mybutton = (Button) findViewById(R.id.mybutton);
/* 绑定接口 */
mybutton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.mybutton:
TextView mytext = (TextView) findViewById(R.id.mytext);
mytext.setText("你好!");
}
}
}
配置文件AndroidManifest.xml代码如下:
android:versionCode="1" android:versionName="1.0" > android:label="@string/app_name" > android:label="@string/app_name" >
运行前后对比,如图2所示:
图2 响应前后结果对比
从上面实现过程可以看出,实现接口到达对事件的处理主要是继承并完成OnClickListener接口中的onClick方法,并且将其绑定在事件源中,从而达到事件处理的效果。
2、内部类事件处理模型
我们将运用接口类实现事件处理模型中的布局文件和配置文件,主要是对Activity中的事件处理方法进行改造,这样写也有利益我们学习。
内部类事件处理模型的Activity代码如下:
package com.wjy.usersrc;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity extends Activity {
TextView mytext = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 以下是定义Button按钮 */
Button mybutton = (Button) findViewById(R.id.mybutton);
mytext = (TextView) findViewById(R.id.mytext);
mybutton.setOnClickListener(new clicklistener());
}
class Clicklistener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.mytext:
mytext.setText("你好");
}
}
}
}
备注:Clicklistener类也可以做成一个普通的类,不一定必须做成内部类,做成普通类完全与内部类效果一样。
3、匿名内部类事件处理模型
其实内匿名内部类处理方式在官方采用的源代码中也应用非常多,下面将以上事件处理过程通过匿名内部类实现,它的布局文件和配置文件与前面应用的一样,只是在Activity中的事件处理代码有所不同,其代码如下:
package com.wjy.usersrc;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 以下是定义Button按钮 */
Button mybutton = (Button) findViewById(R.id.mybutton);
final TextView mytext = (TextView) findViewById(R.id.mytext);
mybutton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.mytext:
mytext.setText("你好!");
}
}
});
}
}
通过以上三种方式我们可以看出,事件处理的模型都是实现接口中的onClick方法,并且绑定于特定的事件源,从而达到事件的处理。 其中,接口实现方法和内部类都是通过继承接口OnClickListener中的onClick方法;匿名内部类实现方法则是通过覆盖onClick方法。
三、Activity中常见的事件
从处理事件过程来说,Activity是一个事件源,了解其中可能出现的事件能够为开发服务,下面我们将对Activity中常见的事件进行分析,常见的事件包括:触摸事件、键盘事件和菜单事件。
1、触摸事件
Android系统中,支持触摸屏的开发,触摸屏事件主要是通过运行事件(MotionEvent)接收消息,若触摸事件源是Activity的话则需要重写方法:
以下以界面中事件来源主要包括按钮和触摸,响应程序如下所示:
package com.wjy.usersrc;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestActivity extends Activity {
TextView mytext01 = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 以下是定义Button按钮 */
mytext01 = (TextView) findViewById(R.id.mytext01);
Button mybutton01 = (Button) findViewById(R.id.mybutton01);
Button mybutton02 = (Button) findViewById(R.id.mybutton02);
mybutton02.setOnClickListener(new clicklistener());
mybutton01.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mytext01.setText("mybutton01");
}
});
}
class clicklistener implements OnClickListener {
@Override
public void onClick(View v) {
if (v.getId() == R.id.mybutton02)
mytext01.setText("mybutton02");
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
TextView mytext02=(TextView)findViewById(R.id.mytext02);
int Action=event.getAction();
float x=event.getX();
float y=event.getY();
mytext01.setText("Action is:"+Action);
mytext02.setText("Postion is:"+"("+x+
return true;
}
}
其布局文件如下:
android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> android:layout_width="165dp" android:layout_height="38dp" android:text="TextView" />
触摸屏幕的响应结果如下图3所示:
图3 触摸屏幕(除按钮以外的区域)响应结果
2、菜单事件
Android的菜单事件与网页中的菜单事件相似,正常情况下都是隐藏的,其主要目的是节省空间,而要调用的时候刚点击menu按钮就弹出来。编写菜单事件一般情况下分成两步:
1)创建和初始化菜单
2)菜单项事件处理
以下是增加了三个子菜单的示例代码:
package com.wjy.java;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class UserActivity extends Activity {
private TextView mytext = null;
private final int first = Menu.FIRST;
private final int second = Menu.FIRST + 1;
private final int third = Menu.FIRST + 2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mytext = (TextView) findViewById(R.id.mytext);
mytext.setText("初始状态");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// 第一个int类型的group ID参数,代表的是组概念,你可以将几个菜单项归为一组,以便更好的以组的方式管理你的菜单按钮。
// 第二个int类型的item ID参数,代表的是项目编号。
// 这个参数非常重要,一个item ID对应一个menu中的选项。在后面使用菜单的时候,就靠这个item ID来判断你使用的是哪个选项。
// 第三个int类型的order ID参数,代表的是菜单项的显示顺序。默认是0,表示菜单的显示顺序就是按照add的显示顺序来显示。
// 第四个String类型的title参数,表示选项中显示的文字。
menu.add(0, first, 0, "第一个");
menu.add(0, second, 0, "第二个");
menu.add(0, third, 0, "第三个");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case first:
mytext.setText("这是第一个子菜单");
return true;
case second:
mytext.setText("这是第二个子菜单");
return true;
case third:
mytext.setText("这是第三个子菜单");
return true;
}
return super.onOptionsItemSelected(item);
}
}
运行结果如图3所示:
图4 菜单示例运行结果
以上简单介绍了下事件、事件源以及事件处理过程,它是编写一个优秀应用程序的必要知识准备。常用见的事件源基本上都是应用JavaSE的界面事件处理方式,即实现onClick()方法,最终实现事件处理的效果,而在Activity中的一些常用事件的处理只需要完成Activity中的一个方法的覆盖就能实现其功能。
更多相关信息请参考http://blog.sina.com.cn/u/2726952293。