第3章Android的事件处理3.1事件处理概述•Android提供两套了事件处理机制:▫a、基于监听器的的事件处理:主要做法就是为Android界面组件绑定特定的事件监听器。▫b、基于回调的事件处理:主要做法是重写Android组件特定的回调方法,或者重写Activity的回调方法。Android为绝大部分组件都提供了事件响应的回调方法。3.2基于监听器的事件处理•事件监听的处理模型中,主要涉及三类对象:▫a、事件源(EventSource):事件发生的场所,通常就是各个组件,例如按钮、窗口、菜单等。▫b、事件(Event):事件封装了界面组件上发生的特定事件(通常就是一次用户操作)。如果程序需要获得界面组件上所发生事件的相关信息,一般通过Event对象来取得。▫c、事件监听器(EventListener):负责监听事件源所发生的事件,并对各种事件做出相应的响应。•实例•\codes\03\3.2\EventQs•在publicvoidonClick(Viewv)参数中,只有事件源,而没有事件,对于复杂事件,则需要传递事件信息,如键盘事件、触摸事件。•实例:控制飞机移动•\codes\03\3.2\Plane•//去掉窗口标题requestWindowFeature(Window.FEATURE_NO_TITLE);//supportRequestWindowFeature•//全屏显示getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);•//定义飞机图片plane=BitmapFactory.decodeResource(context.getResources(),R.drawable.plane);•//获得屏幕宽和高WindowManagerwindowManager=getWindowManager();Displaydisplay=windowManager.getDefaultDisplay();DisplayMetricsmetrics=newDisplayMetrics();display.getMetrics(metrics);•//KEYCODE判断:•KeyEvent.KEYCODE_W•//设置可以获取焦点•setFocusable(true);•Android为不同的界面组件提供了不同的监听器接口,通常以内部类的形式存在,以View为例:•在程序中实现事件监听器,通常有如下几种形式:▫内部类▫外部类▫Activity本身作为事件监听器类▫匿名内部类形式3.2.4外部类作为事件监听器类•使用外部类形式比较少见,原因:▫事件监听器通常属于特定的GUI界面,定义成外部类不利于提高程序的内聚性▫外部类不能自由访问GUI界面的类中的组件,编程不够简洁•但如果某个事件监听器需要被多个GUI界面所共享,则可以考虑使用外部类形式。•实例:长按后发送短信•\codes\03\3.2\SendSms//获取短信管理器SmsManagersmsManager=SmsManager.getDefault();//创建发送短信的PendingIntentPendingIntentsentIntent=PendingIntent.getBroadcast(act,0,newIntent(),0);//发送文本短信smsManager.sendTextMessage(addressStr,null,contentStr,sentIntent,null);•在androidmanifest.xml文件中配置权限:•uses-permissionandroid:name=android.permission.SEND_SMS/•3.2.5Activity本身作为监听器▫不太常见,容易造成程序结构混乱。▫实例:\codes\03\3.2\ActivityListener•3.2.6匿名类▫实例:\codes\03\3.2\AnonymousListener•3.2.7绑定到标签▫实例:\codes\03\3.2\BindingTag3.3基于回调的事件处理•在回调机制中,当用户组GUI组件上激发某个事件时,组件自己特定的方法会处理该事件。•为了使用回调机制处理事件,我们需要重写该类的事件处理方法。3.3.1回调机制与监听机制•Android为所有的GUI组件提供了事件处理的回调方法,以View为例:▫onKeyDown(intkeyCode,KeyEventevent)▫onKeyLongPress(intkeyCode,KeyEventevent)▫onKeyShortcut(intkeyCode,KeyEventevent)▫onKeyUp(intkeyCode,KeyEventevent)▫onTouchEvent(MotionEventevent)▫onTrackballEvent(MotionEventevent)•实例:自定义Button重写onKeyDown•\codes\03\3.3\CallbackHandler•几乎所有基于回调事件处理方法都有一个boolean类的返回值,该返回值是用来表示处理方法是否能完全处理该事件。▫如果返回的是true,表示该事件已完全处理,不会再传播▫如果返回的是false,表示该事件没有完全处理,需要继续传播•实例:事件从Button传播到Activity•\codes\03\3.3\Propagation▫当该组件上发生某个按键被按下的事件时,Android系统最先触发的应该是该按键上绑定的事件监听器,接着才触发该组件提供的事件回调方法,然后还会传播到该组件所在的Activity3.3.3重写onTouchEvent•将上一章“实例:跟随手指的小球”改成基于回调的实现•实例:•\codes\03\3.3\CustomView3.4响应系统设置的事件•在开发Android应用时,有时候可能需要让应用程序随系统设置而进行调整,比如判断系统的屏幕方向、判断系统方向的方向导航设备等3.4.1Configuration类简介•Configuration类专门描述手机设备上的配置信息,这些配置信息既包括用户特定的配置项,也包括系统的动态设备配置。•程序中可调用Activity的如下方法来获取Configuration对象//获取系统的Configuration对象Configurationcfg=getResources().getConfiguration();•该对象的属性代表的配置信息:▫fontScale:获取当前用户设置的字体的缩放因子。▫keyboard:获取当前设备所关联的键盘类型。该属性的返回值:KEYBOARD_12KEY(只有12个键的小键盘)、KEYBOARD_NOKEYS、KEYBOARD_QWERTY(普通键盘)▫keyboardHidden:该属性返回一个boolean值用于标识当前键盘是否可用。该属性不仅会判断系统的硬件键盘,也会判断系统的软键盘(位于屏幕)。▫locale:获取用户当前的Locale.▫mcc:获取移动信号的国家码▫mnc:获取移动信号的网络码▫navigation:判断系统上方向导航设备的类型。该属性的返回值:NAVIGATION_NONAV(无导航)、NAVIGATION_DPAD(DPAD导航)NAVIGATION_TRACKBALL(轨迹球导航)、NAVIGATION_WHEEL(滚轮导航)▫orientation:获取系统屏幕的方向。该属性的返回值:ORIENTATION_LANDSCAPE(横向屏幕)、ORIENTATION_PORTRAIT(竖向屏幕)▫touchscreen:获取系统触摸屏的触摸方式。该属性的返回值:TOUCHSCREEN_NOTOUCH(无触摸屏)、TOUCHSCREEN_STYLUS(触摸笔式触摸屏)、▫TOUCHSCREEN_FINGER(接受手指的触摸屏)•实例:获取系统设备状态•\codes\03\3.4\ConfigurationTest3.4.2响应系统设置更改•Activity的setRequestedOrientation方法可以修改屏幕方向。•重写Activity的onConfigurationChanged,可以响应系统设置更改。•实例:监听屏幕方向改变•\codes\03\3.4\ChangeCfg在Activity中配置configChanges属性:android:configChanges=orientation|screenSize3.5Handler消息传递机制•Handler是Android操作系统中的线程通信工具消息MessageQueue将消息发送到消息队列中将消息从消息队列中取出处理•实例:自动播放动画•\codes\03\3.5\HandlerTest3.5.2Handler工作原理•在主线程中向子线程(workerthread)发送消息:Looper.prepare();mHandler=newHandler(){publicvoidhandleMessage(Messagemsg){//processincomingmessageshere}};Looper.loop();•实例:使用新线程计算质数•\codes\03\3.5\CalPrime3.6异步任务•AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.•Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。•由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:▫1)Params:启动任务执行的输入参数类型▫2)Progress:后台任务完成的进度值的类型▫3)Result:后台执行任务完成后返回结果的类型abstractclassAsyncTaskParams,Progress,Result实现AsyncTask实现步骤•1)创建AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,可将它指定为Void•2)根据需要,实现AsyncTask的如下方法:•(1)doInBackground(Params...):重写该方法是后台线程将要完成的任务。该方法可以调用publishProgress(Progress...values)方法更新任务的执行进度。•(2)onProgressUpdate(Progress..values):在doInBackground()方法中调用publishProgress()方法更新任务的执行进度后,将会触发该方法。•(3)onPreExecute():该方法将在执行后台耗时操作前被调用。通常该方法用于完成一些初始化的准备工作,比如在界面上显示进度条等。•(4)onPostExecute(Resultresult):当doInBackground()完成后,系统会自动调用0nPostExecute()方法,并将doInbackground()方法的返回值传给该方法。•3)调用AsyncTask子类的实例的execute(Params...params)开始执行耗时任务。•实例:使用异步任务执行下载•\codes\03\3.6\AsyncTaskTest