Android 的事件处理

时间:2022-12-15 13:12:35

Android 的事件处理

概括:在自学Android的进程中,今天正式步入事件处理。下面将对事件处理的学习过程做一个随学笔记。

一.事件处理概括

android事件处理机制:

  • 基于监听的事件处理
  • 基于回调的事件处理 ->处理通用事件,代码比较简洁

注:基于监听的事件处理比基于回调的事件处理更具优势。

  1. 基于监听的事件处理分工明确,事件源和事件监听有两个类分开执行,因此具有更好的可维护性
  2. Android的事件处理机制保证基于监听的事件监听器会被优先触发

**注:**android还允许用户在界面布局文件中为UI组件的android:onClick属性指定事件监听方法。该方法要在Activity中定义,该方法的参数view代表该UI组件。

XML文件中的实现代码

<Button 
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_below="@+id/textview"
android:onClick="star"
android:text="被监听按键"/>

Activity中代码

 public void star(View souce){
System.out.println("按键被点击了");
}
//方法实现
star(findViewById(R.id.button));

二.基于监听的事件处理

  • Event source:各个组件

  • Event :用户操作

  • Event Listener:监听事件,对事件作出响应

    事件监听器的核心就是所包含的方法-事件处理器(Event Handler)

基于监听的事件处理的步骤:

  1. 获取事件源:如

    Button button = (Button) findViewById(R.id.button)
  2. 注册监听器:调用事件源的setXxxListener(XxxListener),XxxListener为事件监听器。如

    button.setOnClikListener(new myClickListener)
  3. 事件监听器:为一个类,类似上面的myClickListener类。实现监听器的关键就是实现处理器方法onClick(View v)

    class myClickListener implements View.OnClickListener{
    public void onClick{
    //事件处理方法
    }
    }

Android为不同的组件提供不同的监听器接口,这些接口以内部类的方式存在。以View为例:

  • View.OnClickListener:单击事件的事件监听器必须实现的接口
  • View.OnCreateContextMenuListener:创建上下文菜单事件的事件监听放弃必须实现的接口
  • View.OnFocusChangeListener:焦点改变事件监听器必须实现的接口
  • View.OnKeyListener:按键事件的事件监听器必须实现的接口
  • View.OnLOngClickListener:长单击事件的事件监听器必须实现的接口
  • View.OnTouchListener:触摸屏事件的事件监听器必须实现的接口

实现事件监听器的几种形式

  1. 内部类形式:事件监听器为当前类的内部类

    优点:1可以在当前类中复用该监听器

    ​ 2可以*访问类中的所有组件

  2. 外部类形式:事件监听器定义成一个外部类

    优点:时间监听器能够被多个多个GUI所共享

    缺点:1时间监听器通常属于特定的GUI界面,定义成外部类不利于提高程序的内聚性

    ​ 2不能*访问GUI创建类中组件,编程不够简洁

  3. Activity本身作为一个时间监听器

    优点:简洁

    缺点:容易造成程序结构混乱

    实现实例:

    public class xxx extends Activity implements OnClickListener{
    .....
    button.setOnClickListener(this);
    public void onClick(View V){
    //事件处理方法
    }
    }

  4. 匿名内部类:使用匿名内部类创建事件监听器对象

    实现实例:

    button.setOnClickListener(new OnClickListener(){
    public void onClick(){
    //事件处理方法
    }
    });

三.基于回调的事件处理

回调机制:当用户在GUI组件上激发某个事件时,组件自己特定的方法将会处理该事件

为了实现回调机制的事件处理,Android为所有的GUI组件提供了一些事件处理的回调方法,其中View类包含如下方法:

  • boolean onKeyDown(int keyCode , KeyEvent event):当用户在该组件上按下某个按键时触发该方法
  • boolean onKeyLongPress(int keyCode , KeyEvent event):当用户在该组件上长按某个按键时触发该方法
  • boolean onKeyup(int keyCode , KeyEvent event):当用户在该组件上松开某个按键时触发该方法
  • boolean onTouchEvent(MotionEvent event):当用户在该组件上触发触摸屏事件时触发该事件
  • boolean onTackballEvent(MotionEvent event)当用户在该组件上触发轨迹球屏事件时触发该方法

回调事件处理实例:

public class MyButton extends Button
{

public MyButton(Context context , AttributeSet set)
{
super(context , set);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
super.onKeyDown(keyCode , event);
Log.v("-MyButton-" , "the onKeyDown in MyButton");
System.out.println("按键被点击了");
// 返回false,表明并未完全处理该事件,该事件依然向外扩散
return true;
}
}
XML文件
<org.crazyit.event.MyButton
android:id="@+id/bn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="单击我"
/>

基于回调的事件传播

回调事件处理方法的boolean类型返回值:

  • true:表明该方法已完全处理该事件,该事件不会向外传播
  • false:表明该方法未完全处理该事件,该事件会传播出去

四.响应的系统设置的事件

Configuration类:专门用于描述手机设备上的配置信息调用方法:

Configuration cfg = new getResources().getConfiguration();

获得配置的属性有:

  • public float fontScale 获得当前用户设置的字体的缩放因子
  • public int keyboard 获取当前设备所关联的键盘类型。返回值:KEYBOARD_NOKEYS、KEYBOARD_QWERTY(普通电脑键盘)、KEYBOARD_12KEY(小键盘)
  • public int keyboardHidden 返回一boolean值用于标示当前键盘是否可用。系统的硬件或软件键盘可用,返回KEYBOARDHIDDEN_NO,当两者都不可用,返回KEYBOARDHIDDEN_YES
  • public Locale locale 返回用户当前的Locale
  • public int mcc 获取移动信号的国家码
  • public int mnc 获取移动信号的网络码
  • public int navigation 判断系统上方向导航设备的类型。返回:NAVIGATION_NONAV(无导航)、NAVIGATION_DPAD(DPAD导航)、NAVIGATION_TRACKBALL(轨迹球导航)、NAVIGATION_WHEEL(滚轮导航)等
  • public int orientation 获取系统屏幕的方向,返回值:ORIENTATION_LANDSCAPE(横向屏幕)、ORIENTATION_PORTAIT(竖向屏幕)、ORIENTATION_SQUARE(方形屏幕)
  • public int touchscreen 获取系统触摸屏的触摸方式,返回值:TOUCHSCREEN_NOTOUCH(无触摸屏)、TOUCHSCREEN_STYLUS(触摸笔式的触摸屏)、TOUCHSCREEN_FINGER(接收手指的触摸屏)

例如监听屏幕方向的改变:

public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
String screen = newConfig.orientation ==
Configuration.ORIENTATION_LANDSCAPE ? "横向屏幕" : "竖向屏幕";
Toast.makeText(this, "系统的屏幕方向发生改变" + "\n修改后的屏幕方向为:"
+ screen, Toast.LENGTH_LONG).show();
}

在AndroidManifest.xml文件中配置android:configChanges属性

android:configChanges="orientation"

五.Handle消息传递机制

出现的原因:为了解决多个线程并发操作UI组件所引起的线程安全问题,android指定了一条简单的规则:只允许UI线程修改Activity中的UI组件。这样就导致了新启动的线程无法动态的改变改变界面组件的属性值。在android应用开发中,需要让新的线程周期性的改变界面组件的属性值,就需要借助Handler的消息传递机制来实现。

Handler类的主要作用

  1. 在新启动的线程中发送消息
  2. 在主线程中获取、传递消息

Handler类包括如下方法用于发送、处理消息

  • void handleMessage(Message msg) 处理消息的方法,通常被重写
  • final boolean hasMessages(int what) 检查消息队列中是否包含what属性为指定值的消息
  • final boolean hasMessages(int what, Object object) 检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息
  • 多个重载的Message obtainMessage() 获取消息
  • sendEmptyMessage(int what) 发送空消息
  • final boolean sendEmptyMessageDelayed(int what,long delayMills) 指定多少毫秒之后发送空消息
  • final boolean sendMessage(Message msg) 立即发送消息
  • final boolean sendMessageDelayed(Message msg,long delayMills) 定多少毫秒之后发送消息

自动播放动画实例

final Handler myHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 如果该消息是本程序所发送的
if (msg.what == 0x1233)
{
// 动态地修改所显示的图片
show.setImageResource(imageIds[currentImageId++
% imageIds.length]);
}
}
};
// 定义一个计时器,让该计时器周期性地执行指定任务
new Timer().schedule(new TimerTask()
{
@Override
public void run()
{
// 发送空消息
myHandler.sendEmptyMessage(0x1233);
}
}, 0, 5000);

和Handler一起工作的组件:

  • Message:Handler接收和处理的消息对象
  • Looper:读取MessageQueue中的消息,每个线程只能有一个Looper
  • MessageQueue:消息队列
  • Handler:发送消息和处理消息

**注:**Handler发送和处理的消息必须保存在MessageQueue中,而MessageQueue又由Looper负责管理。因此线程中必须有Looper对象

在线程中使用Handler的步骤:

  1. 调用Looperde prepare()方法为当前线程创建Looper对象,同时它的构造其中创建出与之匹配的MessageQueue
  2. 创建Handle子类的实例,重写handleMessage()方法,该方法负责处理来自其他线程的消息
  3. 调用Looper的loop()方法启动Looper
Looper.prepare();
mHandler = new Handler(){
public void handleMesssage(Message msg){

}
};
Looper.loop();

六、异步任务(Async Task)

AsyncTack**