Android 事件处理探险
作者:互联网
Android提供了两套事件处理机制:基于监听的事件处理;基于回调的事件处理
1.基于监听的事件处理
Android的事件处理是一种委派式事件处理方式(事件源将整个事件处理委托给事件监听器),事件监听的处理模型主要涉及:Event Source(事件源)、Event(事件)、Event Listener(事件监听器)。
小技巧: requestWindowFeature(Window.FEATURE_NO_TITLE); // 去掉窗口标题 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏显示
在基于监听的事件处理模型中,事件监听器必须实现事件监听器接口(通常以内部类的形式存在),以View为例,提供了如下几个接口:
View.OnClickListener // 单击事件 View.OnCreateContextMenuListener // 创建上下文菜单事件 View.OnFocusChangeListener // 焦点改变事件 View.OnKeyListener // 按钮事件 View.OnLongClickListener // 长点击事件 View.OnTouchListener // 触摸屏事件
注意:不推荐将业务逻辑实现写在事件监听器中,包含业务逻辑的事件监听器将导致程序的显示逻辑与业务逻辑耦合,增加了后期维护难度。
2.基于回调的事件处理
Android事件处理的回调方法,以View为例,View类包含如下方法:
boolean onKeyDown(int keyCode, KeyEvent event) // 按下 boolean onKeyLongPress(int keyCode, KeyEvent event) // 长按 boolean onKeyUp(int keyCode, KeyEvent event) // 松开 boolean onKeyShortcut(int keyCode, KeyEvent event) // 键盘快捷键触发时 boolean onTouchEvent(MotionEvent event) // 触摸屏事件
基于回调的事件处理机制可通过自定义View来实现,自定义View时重写该View的事件处理方法即可。
对比Android提供了两套事件处理机制,基于监听的事件处理更有优势:可维护性高、保证监听的事件监听器会被优先触发。
基于回调的事件处理更适合于那些比较固定的View。
3.事件传递
所有基于回调的事件处理的回调方法返回true,表明已处理完成,不会继续传递;返回false,表明未处理完成,该事件继续传递下去。
Button bn = (Button) findViewById(R.id.bn); // 为bn绑定事件监听器 bn.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View source, int keyCode, KeyEvent event) { // 只处理按下键的事件 if (event.getAction() == KeyEvent.ACTION_DOWN) { Log.v("-Listener-", "the onKeyDown in Listener"); } return true; // 返回true,表明该事件不会向外传递 } });
当某个键被按下时候,Android最先触发的是该按键上绑定的事件监听器,然后触发该组件提供的事件回调方法,最后传递到该组件所在的Activity。
4.响应系统设置的事件
1)Configuration类
专门用于描述手机设备上的配置信息
获取系统的Configuration对象:
Configuration cfg = getResources().getConfiguration();
2)重写onConfigurationChanged方法可以响应系统设置更改
5.Handler消息传递机制
Handler类的主要机制有两个:在子线程中发送消息;在主线程中获取处理消息。
Handler包含如下方法用于发送处理消息:
void handleMessage(Message msg):处理消息 final boolean hasMessages(int what, Object object):检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息 boolean sendEmptyMessage(int what):发送空消息 boolean sendEmptyMessageDelayed(int what, long delayMillis):延迟发送空消息 boolean sendMessage(Message msg):发送消息 boolean sendMessageDelayed(Message msg, long delayMillis):延迟发送消息
6.Handler、Looper、MessageQueue
Handler、Looper、MessageQueue各自作用如下:
Handler:能发送消息给MessageQueue,并能处理Looper分发给它的消息;
Looper:每个线程只有一个Looper,负责管理MessageQueue,从MessageQueue中取出消息分发给对应的Handler;
MessageQueue:采用先进先出管理Message;
注意:避免在主线程中执行耗时操作,否则会引发ANR异常。
public class MainActivity extends Activity { EditText etNum; ChildThread childThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ... ChildThread = new ChildThread(); childThread.start(); } /** * 定义一个线程类 */ class ChildThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); // 创建Looper对象 mHandler = new Handler() { // 定义处理消息的方法 @Override public void handleMessage(Message msg) { if(msg.what == 1) { // 执行操作 // ... } } }; Looper.loop(); // 启动Looper } } /** * 按钮的点击事件 */ public void down(View view) { Message msg = new Message(); // 创建消息 msg.what = 1; Bundle bundle = new Bundle(); // num = ... bundle.putInt("num" ,num); msg.setData(bundle); childThread.mHandler.sendMessage(msg); // 向新线程中的Handler发送消息 } }
Android为了解决子线程不能更新UI组件的问题,已提供了如下解决方案:
使用Handler实现线程间通信 runOnUiThread方法 View.post方法 View.postDelayed方法
用法如下:
/** * 1.使用Handler实现线程间通信的用法 */ public class MainActivity extends Activity { protected static final int MSG_ONE = 1; protected static final int MSG_TWO = 2; private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ONE: // 执行1的操作 break; case MSG_TWO: // 执行2的操作 break; }; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 耗时操作要在子线程中操作 new Thread() { public void run() { Message message = Message.obtain(); //获取消息的载体 if (condition) { message.what = MSG_ONE; } else { message.what = MSG_TWO; } handler.sendMessage(message); }; }.start(); } } /** * 2.runOnUiThread方法的用法 */ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 耗时操作要在子线程中操作 new Thread() { public void run() { //执行耗时操作 //更新主线程UI runOnUiThread(new Runnable() { @Override public void run() { } }); }; }.start(); } }
7.异步加载(AsyncTask)
1)先自己手写一个异步加载框架,其中涵盖了异步加载框架核心原理,如下:
public abstract class MyAsycnTask { private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { postTask(); }; }; /** * 在子线程之前执行的操作 */ public abstract void preTask(); /** * 在子线程之中执行的操作 */ public abstract void doinBack(); /** * 在子线程之后执行的操作 */ public abstract void postTask(); /** * 执行 */ public void execute(){ preTask(); new Thread(){ public void run() { doinBack(); handler.sendEmptyMessage(0); }; }.start(); } }
调用手写异步加载框架
new MyAsycnTask() { @Override public void preTask() { //在子线程之前执行的操作 } @Override public void postTask() { //在子线程之中执行的操作 } @Override public void doinBack() { //在子线程之后执行的操作 } }.execute();
2)系统异步加载框架AsycnTask
系统异步加载框架AsycnTask三个参数:提高兼容性(如果某个泛型参数不需要指定类型,可将其指定为void)
参数1:子线程执行所需的参数;参数2:显示当前的加载进度;参数3:子线程执行的结果;
接下来开始调用系统异步加载框架,用法如下:
new AsyncTask<String, Integer, String>(){ //在子线程之中执行的操作 @Override protected String doInBackground(String... params) { // TODO Auto-generated method stub return null; } //在子线程之前执行的操作 @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); } //在子线程之后执行的操作 @Override protected void onPostExecute(String result) { // TODO Auto-generated method stub super.onPostExecute(result); } //显示当前加载进度 @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); } }.execute();
本篇是对Android界面编程的补充,而且都是高频常用的一些方法机制,建议重点学习。
标签:事件处理,void,探险,Handler,线程,Android,public,View 来源: https://blog.51cto.com/u_15127664/2801900