一、概述
不管是桌面应用还是手机应用,面对的都是用户,经常需要处理用户的操作,为用户的动作提供响应,这种机制就是事件处理
Androd系统提供了两种事件处理机制
a、基于监听的事件处理
b、基于回调的事件处理
二、基于监听的事件处理
a、涉及三个模型
Event Source(事件源,事件发生的场所,通俗地讲就是各个组件,如按钮,菜单)(比如企业发生了火灾)
Event(事件),封装了界面上特定的事情(报警,企业处理不了,要消防局来处理)
EventListener(事件监听器)对事件做出的响应(消防机关的警察来灭火)
例子:模拟飞机的移动
public class PlaneView extends View{ public float cx; public float cy; Bitmap palne; public PlaneView(Context context){ super(context); plane=BitmapFactory.decodeResource(context.getResources(),R.drawable.iclon); setFocusable(true); } //还有两个参数,三个参数的构造方法,在使用xml自定义的控件时,会默认调用第二个构造函数 //在这里省略掉了 public void onDraw(Canvas canvas){ super.onDraw(canvas); Paint p=new Paint(); canvas.drawBitmap(plane,cx,cy,p); }
主Activity
public class PlaneGame extends Activity{ private int speed=10;//飞机的移动速度 public void onCreate(Bundle savedInstanceState){ super.onCreate(); //去标题 //全屏显示 final PlaneView planeView=new PlaneView(this); //根据屏幕的宽高设定飞机的初始位置 planeView.cx=....; planeView.cy=....; planeView.setOnKeyListener( new onKeyListener(){ public boolean onKey(View source,int keyCode,KeyEvent event){ // //根据event.getKeyCode()来分别控制上下左右 (调整成员变量cx,cy达到改变飞机的位置) return true;//planeView已经把把键盘触摸的事件消费了,下面的Activity一边待着去吧 } } } ); } }
三、基于回调的事件处理
定义:相比于监听,回调的事件源和事件监听器统一了,也就是所组件自己就具备处理事件的能力
public class PlaneView extends View{ public float cx; public float cy; Bitmap palne; public PlaneView(Context context){ super(context); plane=BitmapFactory.decodeResource(context.getResources(),R.drawable.iclon); setFocusable(true); } //还有两个参数,三个参数的构造方法,在使用xml自定义的控件时,会默认调用第二个构造函数 //在这里省略掉了 public void onDraw(Canvas canvas){ super.onDraw(canvas); Paint p=new Paint(); canvas.drawBitmap(plane,cx,cy,p); } //增加的代码,重写按键点击的响应 public boolean onKeyDown(int keyCode,KeyEvent event){ super.onKeyDown()keyCode,event; syso("the onkeydown on planeView"); reutrn false;// } }
上面在planeview本身就完成了onkeydown的响应
事件响应顺序:当组件上的事件被触发后,Android系统最先触发的是按键上绑定的事件监听器,接着才触发该组件提供事件的回调方法,然后传播给该组件的Activity,如果任何一个组件处理返回了true,事件就不会继续向外传播了。
比较者:基于回调的事件处理具备有更加好的内聚性,模块化更加强一点,把属于一个组件的事务封装到一起
在handler里也有回调,因此我们把handler补充进来,形成知识连
四、handler消息传递机制
背景:由于手机的性能是有限的,为了Android性能的优化,(效率高一点),Android的UI操作不是线程安全的(线程安全就是同一个时刻只有一个线程操作数据),这就意味着当多个线程共同操作ui控件的时候可能会线程不安全,于是Android规定:只有UI主线程有权利操作UI组件。
为了实现这样的效果:由于新开辟的线程希望修改属性的值,却没有资格,这个尴尬的局面。Android提供了handler来完成对把控件的值修改的任务(回调的方式处理这个事件)
具体的过程就是:开发者只需要重写handler类的消息处理方法,当新启动线程的消息通过handler会加入的消息队列里,handler源源不断地获取这个消息队列里的消息并且一一处理,于是handler就回调了
介绍了handler 和消息队列,还差一个Looper,它就是消息队列的管理者
handler想源源不断地获取队列的message,就需要当前线程(一般是UI线程)有一个Looper对象
奇怪啊,我们主线程编写是好像没看到过Looper,为什么handler还能正常地运行呢?(因为UI线程已经初始化了Looper对象)。
如果当前线程不是UI线程,而是自己搞的一个子线程,开发者需要创建Looper对象,并且调用prepare()方法,这样handler就能正常地工作了(因为Looper已经管理了消息队列)
对Looper源代码的研究
private Looper(){ mQueue=new MessageQueue(); mRun=tru; mThread=Thread,.currentThread(); } //说明Looper不能通过构造函数实例化,Looper在初始化时会指明哪个消息队列,哪个线程
public static final void prepare(){ if(sThreadlocal.get()!=null){ throw new Exception(一个线程里只能创建一个Looper); } sThreadlocal.set(new looper()); }
threadlocal线程范围内数据共享,类似map集合,键值对,
例子:明天补充
今天复习了两种事件,自定义控件,多线程,handler,挺不错啊,加油