无论是桌面应用还是手机应用程序,面对用户的使用,经常需要处理的便是用户的各种动作,也就是需要为用户动作提供响应,这种为用户动作提供响应的机制就是事件处理。

而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的事件处理机制之基于监听的事件处理的更多相关文章

  1. Android的事件处理机制详解(二)-----基于监听的事件处理机制

    基于监听的事件处理机制 前言: 我们开发的app更多的时候是需要与用户的交互----即对用户的操作进行响应 这就涉及到了android的事件处理机制; android给我们提供了两套功能强大的处理机制 ...

  2. Android基础新手教程——3.1 基于监听的事件处理机制

    Android基础新手教程--3.1.1 基于监听的事件处理机制 标签(空格分隔): Android基础新手教程 本节引言: 第二章我们学习的是Android的UI控件,我们能够利用这些控件构成一个精 ...

  3. Android_基于监听的事件处理机制

    一.引言 在经过几天的学习之后, 首先熟悉了几大基本布局以及一些常用控件的使用方法,目前正在学习如何实现一个基本的登录注册界面及其功能,而实现功能就需要我们采用事件处理机制来进行调用事件处理方法.以下 ...

  4. Android零基础入门第34节:Android中基于监听的事件处理

    原文:Android零基础入门第34节:Android中基于监听的事件处理 上一期我们学习了Android中的事件处理,也详细学习了Android中基于监听的事件处理,同时学会了匿名内部类形式,那么本 ...

  5. Android开发之基于监听的事件处理

    在Android 应用开发过程中,常用监听事件如下:(1) ListView事件监听setOn ItemSelectedListener:鼠标滚动时触发setOnItemClickListener: ...

  6. Android学习笔记基于监听的事件处理

    事件处理流程 代码格式: Button btn1 = findViewById(R.id.btn1); btn1.setOnClickListener(new View.OnClickListener ...

  7. 基于监听的事件处理——Activity本身作为事件监听器

    这种形式使用Activity本身作为监听器类,可以直接在Activity类中定义事件处理方法,这种形式非常简洁.但这种做法有两个缺点: 这种形式可能造成程序结构混乱,Activity的主要职责应该是完 ...

  8. android事件处理之基于监听

    Android提供了了两种事件处理方式:基于回调和基于监听. 基于监听: 监听涉及事件源,事件,事件监听器.用注册监听器的方法将某个监听器注册到事件源上,就可以对发生在事件源上的时间进行监听. 最简单 ...

  9. Android的事件处理机制之基于回调的事件处理

    回调机制 如果说事件监听机制是一种委托式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源与事件监听器是统一的,换种方法说事件监听器完全消失了,当用户在GUI组件上激发某个事件 ...

随机推荐

  1. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  2. December 21st, Week 51st Saturday, 2019

    May the odds be ever in your favor. 愿好运永远眷顾你. From The Hunger Games. May we all have good luck, and ...

  3. 吴裕雄--天生自然ORACLE数据库学习笔记:数据导出与导入

    create directory dump_dir as 'd:\dump'; grant read,write on directory dump_dir to scott; --在cmd下 exp ...

  4. 导入spark程序的maven依赖包时,无法导入,报错Unable to import maven project: See logs for details

    问题:导入spark程序的maven依赖包时,无法导入,且报错:0:23 Unable to import maven project: See logs for details 2019-08-23 ...

  5. iOS Common Design Patterns:常用设计模式

    原文:http://www.jianshu.com/p/bf431fff235e 我们经常在编程中使用各种设计模式,在iOS中比较常见的设计模式有:单例模式.委托模式.观察者模式,当然实际上在Coco ...

  6. Linux centosVMware LNMP架构介绍、MySQL安装、PHP安装、Nginx介绍

    一. LNMP架构介绍 和LAMP不同的是,提供web服务的是Nginx 并且php是作为一个独立服务存在的,这个服务叫做php-fpm Nginx直接处理静态请求,动态请求会转发给php-fpm   ...

  7. C语言笔记 13_排序算法

    排序算法 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序(如从大到小.首字母从A到Z)错误就把他们交换过来. 过程 ...

  8. 2020-2-18 restful的学习

    1-1 restful简介及资源的介绍 restful   是什么? 本质:一种软件架构风格 核心:面向资源     解决的问题: 1. 降低开发的复杂性 2. 提高系统的可伸缩性     设计概念和 ...

  9. 「快学springboot」16.让swagger帮忙写接口文档

    swagger简介 官方的介绍 THE WORLD'S MOST POPULAR API TOOLING Swagger is the world's largest framework of API ...

  10. pytest+allure(pytest-allure-adaptor基于这个插件)设计定制化报告

    一:环境准备 1.python3.6 2.windows环境 3.pycharm 4.pytest-allure-adaptor 5.allure2.8.0 6.java1.8 pytest-allu ...