Android的事件处理机制之基于监听的事件处理
无论是桌面应用还是手机应用程序,面对用户的使用,经常需要处理的便是用户的各种动作,也就是需要为用户动作提供响应,这种为用户动作提供响应的机制就是事件处理。
而Android为我们提供了两套强大的响应机制:基于监听的事件处理和基于回调的事件处理。本文这次讨论的便是基于监听的事件处理。
对于Android基于监听的事件处理而言,主要做法就是为Android界面组件绑定特定的事件监听器,除此之外Android还允许在界面文件为UI组件的android:onClick属性指定事件监听方法,通过这种方式指定监听方法时,开发者需要在activity中定义该事件监听方法,当用户单击该UI组件时,系统将会激发android:onClick属性所指定的方法。
监听的处理模型
基于监听的事件处理是一种更“面向对象”的事件处理,这种处理方式与Java的AWT、Swing的处理方式几乎完全相同。
在事件的处理模型中,主要涉及以下三类对象:
- Event Source(事件源):事件发生的场所,通常就是各个组件,例如按钮、窗口、菜单等
- Event(事件):事件封装了界面组件上发生的特定事情(通常就是一次用户操作)。如果程序需要获得界面组件上所发生事件的相关信息。一般通过Event来取得。
- Event Listener(事件监听器):负责监听事件源所发生的事件,并对各种事件做出相应的响应。而这些响应动作实际上就是一系列程序语句,通常以方法的形式组织起来,作为事件监听器的核心——这些方法也被称为事件处理器(Event Handler);
当用户按下一个按钮或者一个菜单项时,这些动作便会激发一个相应的事件,该事件就会触发事件源上注册的事件监听器,事件监听器调用对应的事件处理器来做出相应的相应。
基于监听的事件处理机制是一种委派式(Delegation)事件处理方式:普通组件(事件源)将整个事件处理委托给特定对象(事件监听器);当该事件源发生指定事件时,就通知所委派的事件监听器,由事件监听器来处理整个事件。
基于监听的事件处理模型涉及三个成员:事件源、事件和事件监听器,其中事件源最容易创建,任意界面组件都可以作为事件源;事件的产生无需程序员关心,它是由系统自动产生的;所以实现事件监听器是整个事件处理的核心。
内部类作为事件监听器类
使用内部类可以在当前类中复用该监听器类;因为监听器类是外部类的内部类,所以可以自由访问外部类的所有界面组件。这也是内部类作为监听器的优势。下面是一个简单的内部类处理模型,先看布局代码,该布局中只定义了两个组件一个文本框和一个按钮。
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:textSize="18sp"/>
<Button
android:id="@+id/bn"
android:text="单击我"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
下面是程序的Activity:
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取应用程序中的bn按钮
Button bn = findViewById(R.id.bn);
// 为按钮绑定事件监听器
bn.setOnClickListener(new MyClickListener()); // ①
}
// 定义一个单击事件的监听器
class MyClickListener implements View.OnClickListener
{
// 实现监听器类必须实现的方法,该方法将会作为事件处理器
@Override
public void onClick(View v)
{
TextView txt = findViewById(R.id.txt);
txt.setText("bn按钮被单击了!");
}
}
}
外部类作为事件监听器类
使用外部类定义事件监听器类的形式比较少见,主要因为如下两个原因:
- 事件监听器通常属于特定的GUI界面,定义成外部类不利于提高程序的内聚性。
- 外部类形式的事件监听器不能自由访问创建GUI界面的类的组件,编程不够简洁。
如果某个事件监听器确实需要被多个GUI界面所共享,而且主要是完成某种业务逻辑的实现,则可以考虑使用外部类的形式来定义事件监听器类。
下面的程序定义了一个外部类作为OnlongClickListener类,该事件监听器实现了发送短信的功能。界面文件主要由三个组件构成:两个编辑框和一个button。
<EditText
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请填写收信号码"
android:inputType="phone" />
<EditText
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请填写短信内容"
android:lines="3" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="发送" />
SendSmsListener.java
public class SendSmsListener implements View.OnLongClickListener
{
private Activity act;
private String address;
private String content;
public SendSmsListener(Activity act, String address, String content)
{
this.act = act;
this.address = address;
this.content = content;
}
@Override
public boolean onLongClick(View source)
{
// 获取短信管理器
SmsManager smsManager = SmsManager.getDefault();
// 创建发送短信的PendingIntent
PendingIntent sentIntent = PendingIntent.getBroadcast(act,
0, new Intent(), 0);
// 发送文本短信
smsManager.sendTextMessage(address, null,
content, sentIntent, null);
Toast.makeText(act, "短信发送完成", Toast.LENGTH_LONG).show();
return false;
}
}
上面的事件监听器类没有与任何GUI界面耦合,创建该监听器对象时需要传入两个String对象和一个Activity对象,其中第一个String对象用于作为收信人号码,第二个String用于作为短信内容。
public class MainActivity extends Activity
{
private EditText address;
private EditText content;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取页面中收件人地址、短信内容
address = findViewById(R.id.address);
content = findViewById(R.id.content);
Button bn = findViewById(R.id.send);
// 使用外部类的实例作为事件监听器
bn.setOnLongClickListener(new SendSmsListener(this,
address.getText().toString(), content.getText().toString()));
}
}
实际上不推荐将业务逻辑实现写在事件监听器中,包含业务逻辑的事件监听器将导致程序的显示逻辑和业务逻辑耦合,从而增加程序后期的维护难度。如果确实有多个事件监听器需要实现相同的业务逻辑功能,则可以考虑使用业务逻辑组件来定义业务逻辑功能,再让事件监听器来调用业务逻辑组件的业务逻辑方法。
Activity本身作为事件监听器类
这种形式使用Activity本身作为事件监听器类,可以直接在Activity类中定义事件处理器方法。这种形式非常简洁,但这种做法有个缺点:这种形式可能造成程序结构混乱,Activity的主要职责时完成界面初始化工作,但是此时还需包含事件处理器方法,从而引起混乱。
public class MainActivity extends Activity implements View.OnClickListener
{
private TextView show;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = findViewById(R.id.show);
Button bn = findViewById(R.id.bn);
// 直接使用Activity作为事件监听器
bn.setOnClickListener(this);
}
// 实现事件处理方法
@Override
public void onClick(View v)
{
show.setText("bn按钮被单击了!");
}
}
上面的程序让Activity类实现了View.OnClickListener事件监听器接口,从而可以在该Activity类中直接定义事件处理器方法:onClick。当为某个组件添加该事件监听器对象时,直接使用this作为事件监听器对象即可。
Lambda表达式作为事件监听器类
大部分时候事件处理器都没有什么复用价值(可复用代码通常被抽象成了业务逻辑方法),因此大部分时候事件监听器只是临时使用一次,所以使用Lambda表达式形式的监听器更合适。实际上,这种形式时目前使用最广泛的事件监听器形式。
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView show = findViewById(R.id.show);
Button bn = findViewById(R.id.bn);
// 使用Lambda表达式作为事件监听器
bn.setOnClickListener(view -> show.setText("bn按钮被单击了!"));
}
}
上面程序中的粗体字代码使用Lambda表达式创建了一个事件监听器对象,得益于Lambda表达式的简化写法,如果Lambda表达式的执行体只有一行代码,程序可以省略Lambda表达式的花括号。
直接绑定到标签
Android还有一种更简单的绑定事件监听器的方式,那就是直接在界面布局文件中为指定标签绑定事件处理方法。界面组件如下:
<TextView
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="18sp" />
<!-- 在标签中为按钮绑定事件处理方法 -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickHandler"
android:text="单击我" />
上面的粗体字代码为界面的Button按钮绑定了一个事件处理方法:clickHandler,这就意味着开发者需要在该节目布局对应的Activity中定义一个clickHandler方法,该方法将会负责处理该按钮上的单击事件。
MainActivity.java
public class MainActivity extends Activity
{
private TextView show;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = findViewById(R.id.show);
}
// 定义一个事件处理方法
// 其中source参数代表事件源
public void clickHandler(View source)
{
show.setText("bn按钮被单击了");
}
}
注:本博部分内容参考《疯狂Android讲义》一书,侵权必删
Android的事件处理机制之基于监听的事件处理的更多相关文章
- Android的事件处理机制详解(二)-----基于监听的事件处理机制
基于监听的事件处理机制 前言: 我们开发的app更多的时候是需要与用户的交互----即对用户的操作进行响应 这就涉及到了android的事件处理机制; android给我们提供了两套功能强大的处理机制 ...
- Android基础新手教程——3.1 基于监听的事件处理机制
Android基础新手教程--3.1.1 基于监听的事件处理机制 标签(空格分隔): Android基础新手教程 本节引言: 第二章我们学习的是Android的UI控件,我们能够利用这些控件构成一个精 ...
- Android_基于监听的事件处理机制
一.引言 在经过几天的学习之后, 首先熟悉了几大基本布局以及一些常用控件的使用方法,目前正在学习如何实现一个基本的登录注册界面及其功能,而实现功能就需要我们采用事件处理机制来进行调用事件处理方法.以下 ...
- Android零基础入门第34节:Android中基于监听的事件处理
原文:Android零基础入门第34节:Android中基于监听的事件处理 上一期我们学习了Android中的事件处理,也详细学习了Android中基于监听的事件处理,同时学会了匿名内部类形式,那么本 ...
- Android开发之基于监听的事件处理
在Android 应用开发过程中,常用监听事件如下:(1) ListView事件监听setOn ItemSelectedListener:鼠标滚动时触发setOnItemClickListener: ...
- Android学习笔记基于监听的事件处理
事件处理流程 代码格式: Button btn1 = findViewById(R.id.btn1); btn1.setOnClickListener(new View.OnClickListener ...
- 基于监听的事件处理——Activity本身作为事件监听器
这种形式使用Activity本身作为监听器类,可以直接在Activity类中定义事件处理方法,这种形式非常简洁.但这种做法有两个缺点: 这种形式可能造成程序结构混乱,Activity的主要职责应该是完 ...
- android事件处理之基于监听
Android提供了了两种事件处理方式:基于回调和基于监听. 基于监听: 监听涉及事件源,事件,事件监听器.用注册监听器的方法将某个监听器注册到事件源上,就可以对发生在事件源上的时间进行监听. 最简单 ...
- Android的事件处理机制之基于回调的事件处理
回调机制 如果说事件监听机制是一种委托式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源与事件监听器是统一的,换种方法说事件监听器完全消失了,当用户在GUI组件上激发某个事件 ...
随机推荐
- python记录点
python记录点 文件编码 Unicode使用最少2个字节(1个字节=1BYTE=8bit=一个长度为8的二进制数) 来表示字母和符号等,有时候是4个字节. UTF-8是对Unicode编码的压缩和 ...
- 包装类和toString和static关键字
包装类 针对八种基本数据类型定义的引用类型. 有类的特点,可以调用类中的方法. 基本数据类型 包装类 boolean Boolean byte Byte short Short int Integer ...
- ios APP进程杀死之后和APP在后台接收到推送点击跳转到任意界面处理
https://www.jianshu.com/p/ce0dc53eb627 https://www.cnblogs.com/er-dai-ma-nong/p/5584724.html github: ...
- Spring boot 2.x 中使用redis
一.添加Maven 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...
- CVPR 2019 行人检测新思路:
CVPR 2019 行人检测新思路:高级语义特征检测取得精度新突破 原创: CV君 我爱计算机视觉 今天 点击我爱计算机视觉置顶或标星,更快获取CVML新技术 今天跟大家分享一篇昨天新出的CVPR 2 ...
- python随机函数.2020.2.26
随机生成函数: import random //首先要引用random模板 print(random.randint(0,9)) //random的语法 random.randint(0,9 ...
- AngularJS四大特征
AngularJS四大特征 1.MVC模式 Angular遵循软件工程的MVC模式,并鼓励展现,数据,和逻辑组件之间的松耦合.通过依赖注入(dependency injection),Angular为 ...
- Django 学习之内置Admin
一.Admin组件 Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: Django Admin内部依赖: 依赖APP: django.contrib.au ...
- MySQL 之基础操作及增删改查等
一:MySQL基础操作 使用方法: 方式一: 通过图型界面工具,如 Navicat,DBeaver等 方式二: 通过在命令行敲命令来操作 SQL ( Structure query language ...
- 浅谈脱壳中的附加数据问题(overlay)
Author:Lenus -------------------------------------------------- 1.前言 最近,在论坛上看到很多人在弄附加数据overlay的问题,加上 ...