读 Beginning Android Games 2nd Edition (六) 创建键盘事件处理类

来源:互联网 发布:java 短信验证码校验 编辑:程序博客网 时间:2024/04/30 02:59
package com.badlogic.androidgames.framework.impl;import java.util.ArrayList;import java.util.List;import android.view.View;import android.view.View.OnKeyListener;import com.badlogic.androidgames.framework.Input.KeyEvent;import com.badlogic.androidgames.framework.Pool;import com.badlogic.androidgames.framework.Pool.PoolObjectFactory;public class KeyboardHandler implements OnKeyListener {    boolean[] pressedKeys = new boolean[128]; //用于储存按钮的按下状态,按下/非按下    Pool<KeyEvent> keyEventPool;    List<KeyEvent> keyEventsBuffer = new ArrayList<KeyEvent>();        List<KeyEvent> keyEvents = new ArrayList<KeyEvent>();        public KeyboardHandler(View view) {        PoolObjectFactory<KeyEvent> factory = new PoolObjectFactory<KeyEvent>() {            public KeyEvent createObject() {                return new KeyEvent();            }        };        keyEventPool = new Pool<KeyEvent>(factory, 100);        view.setOnKeyListener(this);        view.setFocusableInTouchMode(true);        view.requestFocus();    }    public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {        if (event.getAction() == android.view.KeyEvent.ACTION_MULTIPLE)            return false;        synchronized (this) {            KeyEvent keyEvent = keyEventPool.newObject();            keyEvent.keyCode = keyCode;            keyEvent.keyChar = (char) event.getUnicodeChar();            if (event.getAction() == android.view.KeyEvent.ACTION_DOWN) {                keyEvent.type = KeyEvent.KEY_DOWN;                if(keyCode > 0 && keyCode < 127)                    pressedKeys[keyCode] = true;            }            if (event.getAction() == android.view.KeyEvent.ACTION_UP) {                keyEvent.type = KeyEvent.KEY_UP;                if(keyCode > 0 && keyCode < 127)                    pressedKeys[keyCode] = false;            }            keyEventsBuffer.add(keyEvent);        }        return false;    }    public boolean isKeyPressed(int keyCode) {        if (keyCode < 0 || keyCode > 127)            return false;        return pressedKeys[keyCode];    }    public List<KeyEvent> getKeyEvents() {        synchronized (this) {            int len = keyEvents.size();            for (int i = 0; i < len; i++) {                keyEventPool.free(keyEvents.get(i));            }            keyEvents.clear();            keyEvents.addAll(keyEventsBuffer);            keyEventsBuffer.clear();            return keyEvents;        }    }}

此类使用了前一篇中的对象池类,用于缓存KeyEvent实例

类的运行过程可以用图来说明

第一步:我们从UI线程中得到一个新的事件(event).这时池(Pool)里还没有任何东西.所以我们创建一个KeyEvent的实例(KeyEvent1)并插入到keyEventsBuffer list中

UI thread: onKey() ->

           keyEvents = { }, keyEventsBuffer = {KeyEvent1}, pool = { }


第二步:我们调用主线程中的getKeyEvents方法,getKeyEvents方法从keyEventsBuffer list中拿到实例KeyEvent1,并把它插入到keyEvents 
list 并把它返回给调用者
Main thread: getKeyEvents() ->
           keyEvents = {KeyEvent1}, keyEventsBuffer = { }, pool { }


第三步:我们从UI线程中得到另一个事件,在池中仍然没有东西.因此一个新的KeyEvent实例被创建并插入到keyEventsBuffer list中
UI thread: onKey() ->
           keyEvents = {KeyEvent1}, keyEventsBuffer = {KeyEvent2}, pool { }


第四步:主线程再次调用getKeyEvents方法,有趣的事发生了! keyEvents list 仍然保有KeyEvent1实例,介入的循环将把这个事件放入我们的池中,

之后我们清理掉 keyEvents list,然后插入任何的keyEvent实例到keyEventsBuffer,在这种情况下,KeyEvent2就是我们可以反复利用的Key事件

Main thread: getKeyEvents() ->
           keyEvents = {KeyEvent2}, keyEventsBuffer = { }, pool = {KeyEvent1}


第五步:另一个Key事件到达UI线程,这次我们在池中free拿到KeyEvent,重复利用这个对象,避免了垃圾回收

UI thread: onKey() ->
           keyEvents = {KeyEvent2}, keyEventsBuffer = {KeyEvent1}, pool = { }