第3章 Android事件处理 QQ号: QQ群: (Android编程-清华版)

Slides:



Advertisements
Similar presentations
网络应用程序设计 2014 JavaBean. JavaBean 及其属性 JavaBean 就是一种 Java 的组件技术 JavaBean 是 Java 类 JavaBean 通过约定的方法名实现属性功能 简单属性 void setXxx(Type value) Type getXxx() boolean.
Advertisements

7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
面向侧面的程序设计 方林博士 本文下载地址:
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
實驗五:多媒體播放器選單介面.
第四章 Android事件处理机制 QQ群: Q Q号: 倚动软件工厂实验室.
Part 2 開發Android應用程式的流程
UI(用户界面)集训班 Illustrator 高级班.
第 5 章 流程控制 (一): 條件分支.
基于解释性语言的手机跨平台架构 Sloan Yi. Qt MTK.
第二章 JAVA语言基础.
第14章 c++中的代码重用.
全国计算机等级考试 二级基础知识 第二章 程序设计基础.
在PHP和MYSQL中实现完美的中文显示
第10讲 Java面向对象编程基础(4) 教学目标 主要内容.
第九章 字符串.
實驗四:單位轉換程式.
Android + JUnit 單元測試 建國科技大學資管系 饒瑞佶 2012/8/19V4.
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
Ch06 再談選單元件 物件導向系統實務.
使用Android控制Arduino 史先强
第8章 Android内容提供者(ContentProvider)应用
CH7 佈局、按鈕與文字編輯元件.
Android + Service 建國科技大學 資管系 饒瑞佶.
6.4 Notification 通知栏.
實驗十四:顯示與控制地圖.
走进编程 程序的顺序结构(二).
辅导课程六.
第6章 建立Android使用介面 6-1 介面元件的基礎 6-2 Android的事件處理 6-3 按鈕元件 6-4 文字元件
第五讲 四则运算计算器(一) 精品教程《C#程序设计与应用(第2版)清华大学出版社 谭恒松 主编
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
實驗十一:待辦事項程式 (儲存在手機上).
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
SOA – Experiment 2: Query Classification Web Service
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
C#面向对象程序设计 $6 深入理解类.
Chapter 5 Basic UI Design.
本节内容 消息的分发 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
實驗九:延續實驗八, 製作一個完整音樂播放器
实验四、TinyOS执行机制实验 一、实验目的 1、了解tinyos执行机制,实现程序异步处理的方法。
分裂对象模型 C++ otcl.
计算机网络与网页制作 Chapter 07:Dreamweaver CS5入门
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二章 Java语法基础.
iSIGHT 基本培训 使用 Excel的栅栏问题
LOGIX500软件入门 西安华光信息技术有限公司 2008年7月11日.
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
Visual Basic程序设计 第13章 访问数据库
辅导课程十五.
第二章 Java基本语法 讲师:复凡.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
WSAAsyncSelect 模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
《手把手教你学STM32-STemWin》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
Android Speech To Text(STT)
_01自己实现简单的消息处理框架模型 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第2章 Java语言基础.
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
第4章 闪烁霓虹灯--层布局的应用 授课老师:高成珍 QQ号: QQ群: 、
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
第7章 图片定时滑动播放效果 授课老师:高成珍 QQ号: QQ群: 、
第二章 Java基础语法 北京传智播客教育
多个Activity的使用 本讲大纲: 1、使用Bundle在Activity之间交换数据 2、调用另一个Activity并返回结果
Presentation transcript:

第3章 Android事件处理 QQ号:1281147324 QQ群:489059718(Android编程-清华版) 287966120(公共版) 网络资源:http://www.xs360.cn/book

主要内容 1、基于监听的事件处理 2、基于回调的事件处理 5、异步任务处理 事件处理 3、直接绑定到标签 4、Handler消息处理机制

结构导图

本章示例 案例1:简易文本编辑器 案例2:模拟下载过程

3.1 Android的事件处理机制 Android事件处理机制,主要包含以下三种: 1、基于监听的事件处理 2、基于回调的事件处理 3、直接绑定到标签 主要做法是在界面布局文件中为指定标签设置事件属性,属性值是一个方法的方法名,然后再在Activity中定义该方法,编写具体的事件处理代码。

3.1.1 基于监听的事件处理 基于监听的事件处理模型中,主要涉及到三类对象: EventSource(事件源):产生事件的组件即事件发生的场所,如按钮、菜单等; Event(事件):具体某一操作的详细描述,事件封装了操作的相关信息,如果想获得事件源上所发生事件的相关信息,可通过Event对象来取得,例如按键事件按下的是哪个键、触摸事件发生的位置等; EventListener(事件监听器):负责监听用户在事件源上的操作,并对用户的各种操作做出相应的响应,事件监听器中可包含多个事件处理器,一个事件处理器实际上就是一个事件处理方法。

3.1.1 基于监听的事件处理 这三类对象如何协同工作呢? 基于监听的事件处理是一种委托式事件处理; 普通组件(事件源)将整个事件处理委托给特定的对象(事件监听器); 当该事件源发生指定的事情时,系统自动生成事件对象,并通知所委托的事件监听器,由事件监听器相应的事件处理器来处理这个事件。

3.1.1 基于监听的事件处理 基于监听的事件处理模型 按钮被单击 单击 按钮 click() onClickLinstener( ) setOnClickLinstener( ) 按钮 onClick() onClick()

3.1.1 基于监听的事件处理 对委托式事件处理的理解: 委托式事件处理就如同生活中我们每个人的能力都有 限,当碰到一些自己处理不了的事情时,就委托给某个机 构或公司来处理。 首先,你需要把你所遇到的事情和要求向对方描述清 楚,这样,他人才能更好地解决问题; 其次,该机构不止处理你一个人的事,会选派具体的 员工来处理这件事。 其中,我们自己就是事件源,你遇到的事情就是事件, 该机构就是事件监听器,具体解决事情的员工就是事件处 理器。

3.1.1 基于监听的事件处理 基于监听的事件处理模型的编程步骤: Step1:获取普通界面控件(事件源),即被监听的对象; Step2:实现事件监听器类,该监听器类是一个特殊的 Java类,必须实现一个XxxListerner接口; Step3:调用事件源的setXxxListener方法将事件监听器对 象注册给普通组件(事件源)。

3.1.1 基于监听的事件处理 ※实现事件监听器的四种形式: 内部类形式:将事件监听器类定义为当前类的内部类; 外部类形式:将事件监听器类定义成一个外部类; 类自身作为事件监听器类:让Activity本身实现监听器接口,并实现事件处理方法; 匿名内部类形式:使用匿名内部类创建事件监听器对象。

3.1.1 基于监听的事件处理 举例说明事件监听器的四种形式:简易文本编辑器

3.1.1 基于监听的事件处理 (1)内部类的形式 public class MainActivity extends Activity implements OnClickListener { public void onCreate(Bundle savedInstanceState) { ColorListner myColorListner = new ColorListner(); red.setOnClickListener(myColorListner); green.setOnClickListener(myColorListner); blue.setOnClickListener(myColorListner); } private class ColorListner implements OnClickListener { public void onClick(View v) { switch (v.getId()) { case R.id.red: testText.setTextColor(Color.RED); break; case R.id.blue: testText.setTextColor(Color.BLUE); case R.id.green: testText.setTextColor(Color.GREEN); default: 将事件监听器类定义为当前类(MainActivity)的内部类(ColorListner);

3.1.1 基于监听的事件处理 使用内部类有两个优势: 使用内部类可以在当前类中复用该监听器类,即多个事件源可以注册同一个监听器; 使用内部类可以自由访问外部类的所有界面控件,内部类实质上是外部类的成员。 内部类形式比较适合于有多个事件源同时注册同一事件监听器的情形。

3.1.1 基于监听的事件处理 (2)外部类的形式 将事件监听器类定义成一个外部类(SizeListener.java); public class MainActivity extends Activity implements OnClickListener { public void onCreate(Bundle savedInstanceState) { SizeListener mysizeListener=new SizeListener(testText); bigger.setOnClickListener(mysizeListener); smaller.setOnClickListener(mysizeListener); } 将事件监听器类定义成一个外部类(SizeListener.java); public class SizeListener implements OnClickListener { private TextView tv; public SizeListener(TextView tv) { this.tv = tv; } public void onClick(View v) { float f=tv.getTextSize(); switch (v.getId()) { case R.id.bigger: f=f+2; break; case R.id.smaller: f=f-2; default: }(转左侧代码) if(f>=72){ f=72; } if(f<=8){ f=8; tv.setTextSize(f);

3.1.1 基于监听的事件处理 外部类形式较少见的原因: 事件监听器通常属于特定的GUI(图形用户界面),定义成外部类不利于提高程序的内聚性; 外部类形式的事件监听器不能自由访问创建GUI界面中的组件,编程不够简洁。 如果某个事件监听器确实需要被多个GUI界面所共享,而且主要是完成某种业务逻辑的实现,则可以考虑使用外部类的形式来定义事件监听器类。

3.1.1 基于监听的事件处理 (3)类自身作为事件监听器类 让Activity本身实现监听器接口,并实现事件处理方法; public class MainActivity extends Activity implements OnClickListener { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onClick(View v) { Typeface tf=testText.getTypeface(); switch (v.getId()) { case R.id.italic: if(flag==2||flag==3){ testText.setTypeface(Typeface.MONOSPACE ,Typeface.BOLD_ITALIC); flag=3; }else{ testText.setTypeface(Typeface.MONOSPACE, Typeface.ITALIC);//斜体 flag=1; break; …… default: 让Activity本身实现监听器接口,并实现事件处理方法;

3.1.1 基于监听的事件处理 Activity类本身作为事件监听器,就如同生活中,我们自己刚好能够处理某一件事,不需要委托给他人处理,可以直接在Activity类中定义事件处理器方法,这种形式非常简洁。 不推荐使用的原因: 可能造成程序结构混乱,Activity的主要职责应该是完成界面初始化工作,但此时还需包含事件处理器方法,从而引起混乱; 如果Activity界面类需要实现监听器接口,给人感觉比较怪异。

3.1.1 基于监听的事件处理 (4)匿名内部类形式 使用匿名内部类创建事件监听器对象。 public class MainActivity extends Activity implements OnClickListener { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); content = (EditText) findViewById(R.id.content); content.setOnEditorActionListener(new OnEditorActionListener() { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { testText.setText(content.getText().toString()); return false; } });

3.1.1 基于监听的事件处理 匿名内部类中访问局部成员变量时,该成员变量必须是final修饰的,而对于成员变量则没有这个要求。 大部分时候,事件处理器都没有什么复用价值(可复用代码通常都被抽象成了业务逻辑方法),因此大部分事件监听器只是临时使用一次,所以使用匿名内部类形式的事件监听器更合适。实际上,这种形式也是目前使用最广泛的事件监听器形式。

3.1.1 基于监听的事件处理 常见事件监听器接口及其处理方法: 事件 接口 处理方法 描述 单击事件 View.OnClickListener abstract void onClick (View v) 单击组件时触发 View.OnLongClickListener abstract boolean onLongClick (View v) 长按组件时触发 键盘事件 View.OnKeyListener abstract boolean onKey (View v, int keyCode, KeyEvent event) 处理键盘事件 焦点事件 View.OnFocusChangeListener abstract void onFocusChange (View v, boolean hasFocus) 当焦点发生改变时触发 触摸事件 View.OnTouchListener abstract boolean onTouch (View v, MotionEvent event) 产生触摸事件

3.1.1 基于监听的事件处理 View类的常见事件监听器注册方法: 方法 描述 void setOnClickListener (View.OnClickListener l) 注册单击事件 void setOnLongClickListener (View.OnLongClickListener l) 注册长按事件 void setOnKeyListener(View.OnKeyListener l) 注册键盘事件 void setOnFocusChangeListener (View.OnFocusChangeListener l) 注册焦点改变事件 void setOnTouchListener (View.OnTouchListener l) 注册触摸事件 void setOnCreateContextMenuListener( View.OnCreateContextMenuListener l) 注册上下文菜单事件

3.1.2 基于回调的事件处理 如果说事件监听机制是一种委托式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源和事件监听器是统一的,或者说事件监听器完全消失了,当用户在GUI控件上激发某个事件时,控件自己特定的方法将会负责处理该事件。 为了使用回调机制来处理GUI控件上所发生的事件,需要为该组件提供对应的事件处理方法,而Java又是一种静态语言,我们无法为每个对象动态地添加方法,因此只能通过继承GUI控件类,并重写该类的事件处理方法来实现。

3.1.2 基于回调的事件处理 View类的常见回调方法: Android平台中,每个View都有自己处理特定事件的回调方法,开发人员可以通过重写View中的这些回调方法来实现相应的事件。 View类的常见回调方法: boolean onKeyDown (int keyCode, KeyEvent event):接口KeyEvent.Callback中的抽象方法,用于捕捉手机键盘被按下的事件。keyCode为被按下的键值即键盘码,event为按键事件的对象、包含了触发事件的详细信息,如事件的状态、类型、发生的时间等。 boolean onKeyUp (int keyCode, KeyEvent event):用于捕捉手机键盘按键抬起的事件; boolean onTouchEvent (MotionEvent event):该方法在View类中定义,该方法用于处理手机屏幕的触摸事件,包括屏幕被按下、屏幕被抬起、在屏幕中拖动。

3.1.2 基于回调的事件处理 自定义控件的一般步骤 1)定义自己组件的类名,并让该类继承View类或一个现有的View的子类。 2)重写父类的一些方法,通常需要提供一个构造器,构造器是创建自定义控件的最基本方式,当Java代码创建该控件或根据XML布局文件加载并构建界面时都将调用该构造器,根据业务需要重写父类的部分方法。例如onDraw()方法,用于实现界面显示,其他方法还有onSizeChanged()、onKeyDown()、onKeyUp()等。 3)使用自定义的组件,既可以通过Java代码来创建,也可以通过XML布局文件进行创建,在XML布局文件中,该组件的标签是完整的包名+类名,而不再仅仅是原来的类名。

事件处理的传播 如果处理事件的回调方法返回true,表明该处理方法已完全处理该事件,该事件不会传播出去; 几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于标识该处理方法是否能完全处理该事件。 如果处理事件的回调方法返回true,表明该处理方法已完全处理该事件,该事件不会传播出去; 如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件将会继续向外传播。 对于基于回调事件传播而言,某组件上所发生的事情不仅激发该组件上的回调方法,也会触发该组件所在Activity的回调方法(前提是事件能传播到Activity)。

事件处理的传播 当为同一组件,既采用监听模式,同时又采用回调模式,并且重写了该组件所在Activity对应的回调方法,而且程序没有阻止事件传播,即每个方法都返回为false。那么Android系统的调用顺序是什么呢? 最先触发的是该组件所绑定的事件监听器,接着才触发该组件提供的事件回调方法,最后才传播到该组件所在的Activity。如果我们让任何一个事件处理方法返回了true,那么该事件将不会继续向外传播。

事件处理的传播 案例:自定义一个按钮,重写其触摸的回调方法、为其注册触摸事件监听器并重写它所在Activity上的触摸回调方法,观察事件处理顺序。 如何在布局文件中配置自定义的组件? <完整的包名.类名 需要设置的相关属性/> 做一做:改变方法的返回值(将true改为false), 观察控制台输出结果。

3.1.3 直接绑定到标签 Android提供了一种直接在界面布局文件中为指定标签绑定事件处理方法的机制。对于很多Android界面控件而言,它们都支持如onClick、onLongClick等属性,这些属性的属性值是一个形如xxx(View source)方法的方法名。 例如在布局文件中为按钮添加单击事件的处理方法如下: <Button android:layout_width=”wrap_content” android:layout_heigth=”wrap_content” android:text=”单击我” android:onClick=”clickHandler”/>

3.2 Handler消息传递机制 Android平台不允许Activity新启动的线程访问该 Activity里的界面控件,这样就会导致新启动的线程无法动态 改变界面控件的属性值。 但在实际Android应用开发中,尤其是涉及动画的游戏开 发中,需要让新启动的线程周期性地改变界面控件的属性值, 那如何实现呢? 需要借助Handler的消息传递机制实现

3.2 Handler消息传递机制 Handler类的常用方法: 方法 描 述 描 述 public void handleMessage (Message msg) 通过该方法获取、处理消息 public final boolean sendEmptyMessage (int what) 发送一个只含有what标记的空消息 public final boolean sendMessage (Message msg) 发送消息到Handler,通过handleMessage()方法接收和处理 public final boolean hasMessages (int what) 监测消息队列中是否包含标记为what的消息 public final boolean post (Runnable r) 将一个线程添加到消息队列

3.2 Handler消息传递机制 Handler类主要有两个作用: 新启动的线程何时发送消息?主线程又如何去获取并处理消息呢? 在新启动的线程中发送消息; 在主线程中获取、处理消息。 新启动的线程何时发送消息?主线程又如何去获取并处理消息呢? 当需要界面发生变化的时候,在线程中发送消息。 为了让主线程能“适时”地处理新启动的线程所发送的消息,可采用回调的方式来实现——只需重写Handler类中处理消息的方法,当新启动的线程发送消息时,Handler类中处理消息的方法会被自动调用。

3.2 Handler消息传递机制 Handler消息传递程序开发步骤: 1、创建Handler类对象,并重写handleMessage()方法; 2、在新启动的线程中,调用Handler对象的发送消息方法; 3、利用Handler对象的handleMessage()方法接收消息, 然后根据消息的不同执行不同的操作。 发送和处理消息的是同一个Handler对象,自己发送,自己处理。

3.2 Handler消息传递机制 案例:实现一个动态变化的随机数效果。 1、尝试通过子线程改变主线程界面; 2、尝试直接在主线程中实现该功能; 3、使用Handler处理机制实现该功能。

3.3 异步任务处理 AsyncTask是抽象类,AsyncTask定义了三种泛型类型 Params、Progress和Result。 Android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程。不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。 AsyncTask是抽象类,AsyncTask定义了三种泛型类型 Params、Progress和Result。 Params:启动任务执行的输入参数; Progress:后台任务执行的百分比; Result:后台任务执行最终返回结果的类型,如String,Integer等。

3.3 异步任务处理 AsyncTask类中主要方法: onPreExecute():该方法将在执行实际的后台操作前被UI线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。 doInBackground(Params...):将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些比较耗时的后台处理工作。可以调用 publishProgress方法来实时更新任务进度。该方法是抽象方法,子类必须实现。 onProgressUpdate(Progress...):在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 onPostExecute(Result):在doInBackground 执行完成后,onPostExecute 方法将被UI线程调用,后台的计算结果将通过该方法传递到UI线程,并且在界面上展示给用户。 onCancelled():在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。

3.3 异步任务处理 使用AsyncTask类需遵守的准则: Task的实例必须在UI线程中创建; execute(Params...)方法必须在UI线程中调用; 不要手动的调用onPreExecute(), onPostExecute(Result), doInBackground(Params...),onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用; 该task只能被执行一次,否则多次调用时将会出现异常。

程 序 运 行 效 果 分 析

方 法 调 用 顺 序 分 析 注意:其中只有doInBackground()方法,以及publishProgress()方法是在子线程中执行的,其他的方法都是在主线程中执行的,所以可以在这些方法中更新界面组件。