做 uni-app + PDA 项目时,有一个非常常见的问题:
明明只扫了一次商品:
6901234567890
结果系统却执行了两次。
例如入库数量:
原来:10
扫码一次
预期:11
实际:12
甚至出现:
请求接口两次
生成两条记录
播放两次提示音
弹两个 Toast
很多人的第一反应是:
扫码枪是不是发送了两次?
实际上,更多时候问题出在:
扫码监听被注册了两次。
一、最常见原因:页面重复注册监听
例如页面:
onShow
↓
注册扫码监听
用户进入页面:
注册监听 A
跳到其他页面再回来:
onShow 再执行
↓
又注册监听 B
这时候实际上已经存在:
监听 A
监听 B
扫码一次以后:
设备发送一次扫码结果
↓
监听 A 收到
监听 B 也收到
↓
业务执行两次
所以:
扫码一次触发两次,不一定是设备发送了两遍。
很可能只是你的 APP 接收了两遍。
二、onShow 特别容易踩坑
uni-app 页面生命周期里面:
onShow
不是只执行一次。
每次页面重新显示,都可能再次执行。
如果里面直接写:
registerScanListener()
但是没有对应:
unregisterScanListener()
监听数量就可能不断增加。
最后甚至会出现:
第一次扫码 → 1次
重新进入页面
第二次扫码 → 2次
再返回一次
第三次扫码 → 3次
这种情况非常典型。
三、还有一种情况:广播扫码和键盘扫码同时开启
有些 PDA 支持:
Broadcast 模式
Keyboard 模式
甚至可能两个模式同时工作。
一次扫码:
PDA 扫描
↓
广播发送一次
+
模拟键盘又输入一次
如果你的项目同时监听:
Android Broadcast
和:
Keyboard Input
业务层就会收到两个内容完全一样的扫码结果。
这种情况尤其容易被误认为:
插件重复回调。
实际上是设备启用了两个输出通道。
四、还有一种:多个页面同时监听
例如:
首页
↓
注册扫码事件
进入:
入库页面
↓
又注册扫码事件
但是首页监听并没有释放。
这时候扫码:
首页收到
+
入库页面收到
如果两个页面都调用业务接口,就会产生重复操作。
因此扫码这种全局设备能力,最好不要让每个页面随意注册原生监听。
五、业务层还需要做一次防重复
即使底层监听已经处理正确,在企业项目里我仍然建议增加一个简单的防抖机制。
比如同一个条码:
6901234567890
在非常短的时间内连续到达:
0ms → 6901234567890
50ms → 6901234567890
可以根据业务规则判断是否忽略第二次。
但要注意:
不能简单设置“1 秒内所有扫码都忽略”。
因为仓库人员可能真的在高速连续扫描不同商品:
商品 A
商品 B
商品 C
更合理的是结合:
扫码内容
时间
当前业务页面
业务状态
进行判断。
六、推荐的结构
我现在更建议:
PDA / 扫码枪
↓
唯一扫码监听
↓
ScanBridge
↓
标准 ScanResult
↓
当前业务页面
而不是:
页面 A → 注册设备
页面 B → 注册设备
页面 C → 注册设备
这样比较容易统一控制:
注册
注销
页面生命周期
重复扫码
数据来源
我们把这部分整理进了SL-ScanBridge,用于 uni-app / uni-app x Android 项目中的 PDA 广播、2.4G 扫码枪和模拟键盘扫码统一处理。
如果你的项目也出现:
扫一次执行两次
建议第一步不要急着改接口。
先打印:
监听注册次数
扫码回调次数
扫码来源
当前页面
时间戳
插件地址:SL-ScanBridge - DCloud 插件市场
通常很快就能找到问题。