前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 事件处理探险

Android 事件处理探险

作者头像
非著名程序员
发布2018-02-02 13:56:59
6250
发布2018-02-02 13:56:59
举报
文章被收录于专栏:非著名程序员非著名程序员

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界面编程的补充,而且都是高频常用的一些方法机制,建议重点学习。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 非著名程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.基于监听的事件处理
  • 2.基于回调的事件处理
  • 3.事件传递
  • 4.响应系统设置的事件
  • 5.Handler消息传递机制
  • 6.Handler、Looper、MessageQueue
  • 7.异步加载(AsyncTask)
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档