android key事件分发,巧用事件分发机制,和我一起hold住android外围设备

外围输入设备,例如:蓝牙键盘,usb键盘,barcode扫码枪...

由于平时都是在做纯软件程序的开发,博主在需求遇到android设备与外围设备交互时有点不知所措。我最初的思路是这样:既然是蓝牙连接,那不就是socket吗,那么截获他的I/O流然后解析里面的内容...那不就ok啦?

然而事情并没有那么简单,首先解析数据流是一个难点,再一个万一我蓝牙连接换成usb连接,或者wifi,那不就得再改了?

参考了网上的方案后发现,外围设备是通过KeyEvent事件机制android交互的,既然是这样那我就不用再关心外设是通过什么方式连接的,直接截获外设发送的事件,并且还可直接获取到输入内容!

本文将通过一个android设备与扫码枪连接案例来向大家详述android的事件机制

首先看一个我具体使用的类库

a9e3eaf2fe842e954825e74dc2dbd64a.png

我们直接来看看是怎么用的

public class MainActivity extends AppCompatActivity implements BarCodeIpml.OnScanSuccessListener {

//activity实现了BarCodeIpml.OnScanSuccessListener借口,即回调成功时的借口

private BarCodeIpml barCodeIpml = new BarCodeIpml();

private TextView textView;

private TextView mTv;

private static final String TAG="MainActivity";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//设置扫码成功的回调监听

barCodeIpml.setOnGunKeyPressListener(this);

mTv = (TextView) findViewById(R.id.mTv);

}

//重写事件分发的方法

@Override

public boolean dispatchKeyEvent(KeyEvent event) {

if (barCodeIpml.isEventFromBarCode(event)) {

barCodeIpml.analysisKeyEvent(event);

return true;

}

Log.e("keycode",event.getKeyCode()+"");

return super.dispatchKeyEvent(event);

}

//在activity获得焦点时

@Override

protected void onResume() {

super.onResume();

try {

barCodeIpml.hasConnectBarcode();

} catch (DevicePairedNotFoundException e) {

e.printStackTrace();

Log.e(TAG, "badcode枪未连接!");

}

}

//借口的实现,扫码成功后的回调,写你自己的实现

@Override

public void onScanSuccess(String barcode) {

Log.e("mcallback", barcode);

mTv.setText(barcode);

}

//与activity生命周期绑定,防止内存泄漏

@Override

protected void onDestroy() {

super.onDestroy();

barCodeIpml.onComplete();

}

}

从注释和方法的名称我们大概可以判断出各个方法的作用,我们来看其中最关键的一个方法

dispatchKeyEvent(KeyEvent event)

大家首先需要知道,这个方法返回一个boolean

@Override

public boolean dispatchKeyEvent(KeyEvent event) {

if (barCodeIpml.isEventFromBarCode(event)) {

barCodeIpml.analysisKeyEvent(event);

return true;

}

Log.e("keycode",event.getKeyCode()+"");

return super.dispatchKeyEvent(event);

}

当我返回一个true的时候,这个事件就会被我们消费(类库里的主要操作就是获取KeyCode,即外围设备输入的内容),不会再交给系统处理。在以上的代码中我拿到这个事件后我调用类库的方法判断他是否来自外围设备,如果是的话我们自己将其截获处理,不再交给系统,否则的话我们交由系统处理。这个方法大家应该比较熟悉,我们常常用来重写back键或者home键。

之后我们进去dispatchKeyEvent里面看一下,系统是如何处理这个事件的,直接在activity中查看源码

/**

* Called to process key events. You can override this to intercept all

* key events before they are dispatched to the window. Be sure to call

* this implementation for key events that should be handled normally.

*

* @param event The key event.

*

* @return boolean Return true if this event was consumed.

*/

public boolean dispatchKeyEvent(KeyEvent event) {

onUserInteraction();

// Let action bars open menus in response to the menu key prioritized over

// the window handling it

final int keyCode = event.getKeyCode();

if (keyCode == KeyEvent.KEYCODE_MENU &&

mActionBar != null && mActionBar.onMenuKeyEvent(event)) {

return true;

} else if (event.isCtrlPressed() &&

event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '

// Capture the Control-< and send focus to the ActionBar

final int action = event.getAction();

if (action == KeyEvent.ACTION_DOWN) {

final ActionBar actionBar = getActionBar();

if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {

mEatKeyUpEvent = true;

return true;

}

} else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {

mEatKeyUpEvent = false;

return true;

}

}

源码不算复杂,注释说你可以在事件发送到窗口前拦截此事件,但要对关键事件执行,这里说的关键事件可能是back键或者home键。

我们一步一步来做下分析,先来看看onUserInteraction()

/**

* Called whenever a key, touch, or trackball event is dispatched to the

* activity. Implement this method if you wish to know that the user has

* interacted with the device in some way while your activity is running.

* This callback and {@link #onUserLeaveHint} are intended to help

* activities manage status bar notifications intelligently; specifically,

* for helping activities determine the proper time to cancel a notfication.

*

*

All calls to your activity's {@link #onUserLeaveHint} callback will

* be accompanied by calls to {@link #onUserInteraction}. This

* ensures that your activity will be told of relevant user activity such

* as pulling down the notification pane and touching an item there.

*

*

Note that this callback will be invoked for the touch down action

* that begins a touch gesture, but may not be invoked for the touch-moved

* and touch-up actions that follow.

*

* @see #onUserLeaveHint()

*/

public void onUserInteraction() {

}

实现居然是空的,注释上说当事件分发到activity的时候调用,你可以实现这个方法来获知用户是否在和当前activity交互。onUserInteraction()和onUserLeaveHint()是本意是帮助activity更好的管理推送消息,后者将会跟随前者一起调用,上面还说onUserInteraction()可能不会跟随着手指的移动而调用。

由此,我们也知道onUserInteraction()会在事件分发最初的时候调用,我们可以用这和方法监听用户于activity的交互。

我们接着往下看

// Let action bars open menus in response to the menu key prioritized over

// the window handling it

final int keyCode = event.getKeyCode();

if (keyCode == KeyEvent.KEYCODE_MENU &&

mActionBar != null && mActionBar.onMenuKeyEvent(event)) {

return true;

}

首先获取用户的输入内容keyCode ,之后的意图很明显,如果用户点击的是ToolBar或者ActionBar的菜单那直接return了一个true,我们刚刚说过return一个true的意思就是事件不再交给系统处理,return一个false则依旧需要交给系统处理,这里的目的想必就是把我们的事件抛给ToolBar或者ActionBar来处理。

接着往下看

else if (event.isCtrlPressed() &&

event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '

// Capture the Control-< and send focus to the ActionBar

final int action = event.getAction();

if (action == KeyEvent.ACTION_DOWN) {

final ActionBar actionBar = getActionBar();

if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {

mEatKeyUpEvent = true;

return true;

}

} else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {

mEatKeyUpEvent = false;

return true;

}

第一个判断条件event.isCtrlPressed() &&event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '

搞懂了以上的内容我们就可以随意截获事件,并通过KeyCode获知是否点击了虚拟键盘,具体点击的是哪一个键?如果是回车键,那就将其内容通过回调发送给activity,由此来获取外围输入设备的内容。具体可查看 https://github.com/sally519/BarCode-android 中的使用详情。

#小结

好了,我们来总结几个需要特别注意的点

dispatchKeyEvent(KeyEvent event)中,但我们返回了true,则事件将会被消费,不会在有系统处理,当返回false则还要交由系统来处理

onUserInteraction()和onUserLeaveHint()可以用来监听用户的和activity的交互,注意:activity必须是获得焦点的

我们在消费事件的时候需要对注意home键back键等常用的键,如果没有特殊需求,记得将他们抛给系统处理

博主难免有疏忽和遗漏,若有错误或疑点欢迎指正!

以上内容均为原创,欢迎关注博主!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值