Android开发中的UI事件监听处理机制总结:
在Android平台上,捕获用户在界面上的触发事件有很多种方法,View类就提供这些方法。你在使用各种View视图来布局界面时,会发现几个公用的回调方法来捕捉有用的UI触发事件,当事件在某个View对象上被触发时,这些方法会被系统框架通过这个对象所调用,例如:当一个View(如一个Button)被点击,onTouchEvent()方法会在该对象上被调用,所以,为了捕获和处理事件,必须去继承某个类,并重载这些方法,以便自己定义具体的处理逻辑,显然,你更容易明白,为什么在你使用View类时会嵌套带有这些回调方法的接口类,这些接口称为event listeners,它是你去获取UI交互事件的工具在你继承View类,以便建立一个自定义组,也许你想继承Button,你会更普遍使用事件监听来捕捉用户的互动,在种情况下,你可以使用类的event handlers.来预定义事件的处理方法。
View类里的event listener是一个带有回调方法的接口,当UI里的组建是被用户触发时,这些方法会被系统框架所调用。
1.onClick()来自View.OnClickListener 它会被调用当点击这个Item(在触摸模式),或者当光标聚集在这个Item上时按下“确认”键 ,导航键,或者轨迹球。
2.onLongClick()来自View.OnLongClickListener. 它会被调用当长按这个Item(在触摸模式),或者当光标聚集在这个Item上时长按 “确认”键 ,导航键,或者轨迹球。
3.onFocusChange()来自View.OnFocusChangeListener 它会被调用当光标移到或离开这个Item,
4.onKey()来自View.OnKeyListener..它会被调用,当光标移到这个Item,按下和释放一个按键的时候
5.onTouch()来自View.OnTouchListener. 它会被调用 ,在这个Item的范围内点触的时候
6.onCreateContextMenu()来自View.OnCreateContextMenuListener. 在长按时候会被调用。
这些方法和嵌套接口类都是一一对应的,如果确定其中一种方法处理你的互动事件,你需要在Activity中实现这个带有这个方法的接口,并把它作为匿名类,然后,通过实例的View.setXxxListener() 方法来设置监听器(例如,调用setOnClickListener(),来设置OnClickListener做为监听器)
键盘事件:直接覆盖Activity中相应的方法:
//键盘按下事件
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
ToastUtil.showToast(this, keyCode+"");
return super.onKeyDown(keyCode, event);
}
//键盘长按事件
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return super.onKeyLongPress(keyCode, event);
}
//键盘弹起事件
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return super.onKeyUp(keyCode, event);
}
下面是为一个按钮设置监听器的例子:
//实现OnClickListener接口并实现onClick方法
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
}
};
//为按钮注册事件监听器
protected void onCreate(Bundle savedValues) {
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(mCorkyListener);
}
下面这个列子我们会发现用Activity去实现OnClickListener接口,并作为它的一部分,会更方便,而不必去加载额外的类和对象
//在集成Activity的子类中直接实现监听接口
public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}
public void onClick(View v) {
//事件处理
}
}
这里注意一下,以上的例子可以看出onClick()是没有返回值的,但是有些事件处理方法是必须带返回值,它取决于的具体的事件,有些那么做的原因,看下面的例子:
onLongClick()它返回的布尔值表明你已经完成了这个事件的处理,还是应该把它继续传下去。返回true表明已经处理完成并且停止了传递,如果返回为false表明事件还没有完成,或者它还需要继续被传递给其他的监听器。
onKey()它返回的布尔值表明你已经完成了这个事件的处理,还是应该把它继续传下去。返回true表明已经处理完成并且停止了传递,如果返回为false表明事件还没有完成,或者它还需要继续被传递给其他的监听器。
onTouch()它返回的布尔值表明你是否已经完成了这次事件的行动,重要的是后面可能还有很多后续的行动,这样,如果你返回false,表明在接到下一次的后续行动中,你还没有完成之前行为也没有意向去处理随后的行动,因此,在这个事件的后续行动中将不会再被调用。 如fingure手势,或最终行动事件。
记住:我们所关注的事件肯定是发生在高亮聚集的焦点,它从总视图(顶级的)被一级一级的向下传递,直到我们想要关注的组件,当焦点聚集在这个视图(或视图中的子视图)时 ,你能够使用dispatchKeyEvent() 作为一种代替方法,来捕获在视图上的按键事件,你还可以使用onKeyDown()和onKeyUp().来捕获所有事件内的交互活动
注意:在 Android 框架中会调用event handlers先处理事件,然后会适当的传递给二级默认的预定义handlers中;因此 如果返回true,将会停止这个事件的传递,View中默认事件处理方法的回调也会被阻止。因此,当你返回true肯定表明你是要终止这个事件的延续。
如果您建立一个继承于View自定义组件,然后您可以定义一些回调方法用作默认的事件处理程序。该文件中关于Building Custom Components,您会学习一些共用的回调方法用于事件处理,其中包括:
onKeyDown(int, KeyEvent) – Called when a new key event occurs.
onKeyUp(int, KeyEvent) – Called when a key up event occurs.
onTrackballEvent(MotionEvent) – Called when a trackball motion event occurs.
onTouchEvent(MotionEvent) – Called when a touch screen motion event occurs.
onFocusChanged(boolean, int, Rect) – Called when the view gains or loses focus.
当用户在使用方向键或轨迹球浏览用户界面时,有必要给于一个焦点在可操作的组件上(如一个Button),使用户可以看到它将接受输入命令。如果设备有触摸功能,那么,当用户与界面的交互就不再需要有一个高亮在组件上,或一个焦点在view上,因此,模式的互动名为”触摸模式”。对于一个触摸设备,一旦有用户接触屏幕时,该设备将进入触摸模式.在点触某个View后,只有的它的方法isFocusableInTouchMode()返回为真时,才会有聚集焦点,如文本编辑工具。其他的界面只可以点触,但不会聚集焦点(高亮),如button 被点触时就不会聚集焦点,当它被按下时只会调用on-click监听器的回调方法。
任何时候用户接触方向键或者滚动轨迹球时,该设备将退出触摸模式,并聚集焦点,用户可以恢复与用户界面的键盘交互,而不必在屏幕上。触摸模式的状态是由整个系统来维持的(all windows and activities),要查询目前所处的状态,你可以调用isInTouchMode()方法来获得,看看设备目前是否处于触摸模式。
系统框架将处理日常的焦点移动来响应用户的输入,它包刮改变焦点(当界面是被移除,隐藏,或者作为一个新的View变为可用状态),通过isFocusable()这个方法我们可以知道view是否具有接受焦点的资格,也可以通过setFocusable().来设置view接受焦点的资格,对应在触摸模式下,你可以调用isFocusableInTouchMode().来获知是否有焦点来响应点触,也可以通过setFocusableInTouchMode().来设置是否有焦点来响应点触的资格.
系统框架控制焦点移动到另一个组件的算法是在某一方向上邻近的组件,在极个别情况下,默认的算法可能不符合开发者的预想要求,在这种情况下,你可以覆写下列XML属性的布局文件(nextFocusDown,nextFocusLeft,nextFocusRight,nextFocusUp)设置他们的值来明确焦点从当前界面移动下个界面的Id。例如:
<LinearLayout
android:orientation=”vertical”
>
<Button android:id=”@+id/top”
android:nextFocusUp=”@+id/bottom”
/>
<Button android:id=”@+id/bottom”
android:nextFocusDown=”@+id/top”
/>
</LinearLayout>
一般来说,在这个垂直布局,浏览的焦点会从第一个按钮开始,不会是从第二个或者其他的,现在topButtont已经通过nextFocusUp (反之亦然)确定了bottom.
通常如果你想宣布用户界面具有焦点的资格 (如果这个界面在传统上是没有的),可以在xml布局里去加上的android:focusable的属性,并设置它的值,您也可以宣布在触摸模式下具有焦点的资格,同样也只在xml里添android:focusableInTouchMode.的属性,并设置它的值. 当用户请求在某个界面聚集焦点时,会调用requestFocus().这个方法。监听到焦点活动(获得焦点或失去焦点都会被通知),会调用onFocusChange(),这个方法,这也是上面所讨论的Event Listeners。
总结:
对于UI控件事件的处理,需要设定相应的监听器,并实现相应的事件处理程序。这儿有两种实现方法:一是定义一个OnClickListener 类的实例,并使用setOnClickListener等绑定监听器;二是用Activity去实现OnClickListener接口,并作为它的一部分,这样会更方便,省去了加载额外的类和对象的时间。
对于支持触摸屏的手机,可以设定触摸模式的UI,可以使用isInTouchMode()来获得触摸模式的状态。
UI处理的另一个重点是焦点的设定及其切换。焦点设置:通过setFocusable或者setFocusableInTouchMode设置可以接受焦点,通过isFocusable或isFocusableInTouchMode获取是否可以接受焦点;焦点切换:编写XML布局文件的nextFocusDown 等属性设置。
2D画法:
1)定义画板:
public class PuzzleView extends View {
public PuzzleView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
// 当画板大小发生变化时会调用此方法,比draw(Canvas canvas)方法优先调用
public void onSizeChanged(int w, int h, int oldw, int oldh) {
}
//当view对象创建完之后系统会主动调用该方法,canvas是画板
@Override
public void draw(Canvas canvas) {
System.out.println("*****PuzzleView's draw()...");
//Paint是画笔
Paint background = new Paint();
background.setColor(this.getResources().getColor(R.color.puzzle_background));
canvas.drawRect(0, 0, this.getWidth(),this.getHeight(),background);
}
}
2)使用画板:
public class TwoDActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PuzzleView view = new PuzzleView(this);
this.setContentView(view);
}
}
Activity生命周期方法:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()组成。
android数据存储: 4种方式
1. SharedPreferences
底层使用xml文件保存数据, 优点是操作简单,结构简单
缺点是不适宜保存一些复杂,海量数据
2. 文件 + IO
优点: 有java基础就很方便学习
缺点: 操作,检索,更新不方便
3. SQLite android内部数据库
4. 内容提供器
搭建数据共享的桥梁
SharedPreferences存储数据:
1)保存数据:
/*public SharedPreferences getSharedPreferences(String name,int mode)
* 参数:
name - 声明xml文件的名字,如果该文件不存在,在 SharedPreferences.edit(),Editor.commit()后文件被创建.
mode - 对目标xml文件操作的权限.选值有:
1)0 或者Context.MODE_PRIVATE是默认操作,表示只有创建文件的程序对该目标可读可写
2)Context.MODE_WORLD_READABLE:全局读,除了创建文件的程序对该目标可读可写之外,其它程序可以对该文件进行读操作
3)Context.MODE_WORLD_WRITEABLE:全局写,除了创建文件的程序对该目标可读可写之外,其它程序可以对该文件进行写操作
返回:
Returns the single SharedPreferences instance that can be used to retrieve and modify the preference values.
另请参见:
*/
SharedPreferences sp = this.getSharedPreferences("ACCOUNT", Activity.MODE_PRIVATE);
// 如果是要完成写操作, 那么必须先创建 编辑器对象
Editor edit = sp.edit();
// 完成信息的编辑
edit.putString("user","admin");
edit.putString("passwd","123456");
// 提交数据
edit.commit();
2)取出数据:
/*
public abstract String getString (String key, String defValue)
Parameters
key The name of the preference to retrieve.
defValue Value to return if this preference does not exist
*/
SharedPreferences sp = this.getSharedPreferences("ACCOUNT", Activity.MODE_PRIVATE);
// 如果是要完成写操作, 那么必须先创建 编辑器对象
Editor edit = sp.edit();
String name = sp.getString("user","default_name");
String passwd = sp.getString("passwd","default_password");
清除数据:
Editor edit = sp.edit();
edit.clear()
edit.summit();
IO数据存储:
1)保存数据:
FileOutputStream fos = this.openFileOutput("content.txt", Context.MODE_APPEND);
String content = etContent.getText().toString();
fos.write(content.getBytes());
2)读取数据:
FileInputStream fis = this.openFileInput("content.txt");
byte[] buf = new byte[100];
int len = 0;
StringBuffer sb = new StringBuffer();
String s = null;
while((len = fis.read(buf))!=-1){
s = new String(buf,0,len);
sb.append(s);
};
SQLite步骤:
1)创建一个SQLiteDatabase对象
SQLiteDatabase sqlite = this.openOrCreateDatabase("gjun",Context.MODE_PRIVATE, null);
2)执行SQL语句:
String sql = "create table users(id integer primary key,name varchar(20)," +
"password varchar(20),email varchar(20),phone varchar(20))";
sqlite.execSQL(sql);
A、插入操作:
//插入数据第一种方式:
/*String sql = "insert into users(id,name,password,email,phone) values(?,?,?,?,?)";
sqlite.execSQL(sql, new Object[]{id++,"stone","123","stone@163.com","13631363270"});
//插入数据第二种方式:
ContentValues cv = new ContentValues();
cv.put("id", id++);
cv.put("name", "Lily");
cv.put("password", "123");
cv.put("email", "Lily@163.com");
cv.put("phone", "13631363280");
sqlite.insert("users", null, cv);
B、删除或者更新操作:
String sql = "delete from users";
sqlite.execSQL(sql);
C、查询操作:
String sql = "select * from users";
Cursor cursor = sqlite.rawQuery(sql,null);
while(cursor.moveToNext()){
System.out.println(cursor.getInt(0)+"\t"+cursor.getString(1)+"\n");
}
cursor.close();
3)关闭数据库:
public void onDestroy() {
String sql = "drop table users";
sqlite.execSQL(sql);
System.out.println("*********drop table successfully*********");
//关闭数据库
sqlite.close();
//删除数据库
this.deleteDatabase("gjun");
}
使用终端查看sqlite步骤:
D:\stone\course\3G\android-sdk-windows\tools>adb shell
# cd data/data
cd data/data
# cd demo.abc
# cd databases
# sqlite3 gjun
sqlite> .table