
本文介绍如何基于 code-scanner 库,通过回调驱动方式实现多轮 QR 码扫描——避免阻塞主线程、不依赖 wait/notify,而是利用 onDecoded 回调自然触发下一次扫描,确保线程安全与流程可控。
本文介绍如何基于 code-scanner 库,通过回调驱动方式实现多轮 qr 码扫描——避免阻塞主线程、不依赖 `wait/notify`,而是利用 `ondecoded` 回调自然触发下一次扫描,确保线程安全与流程可控。
在 Android 开发中,QR 码扫描本质上是异步事件驱动过程:摄像头持续预览 → 检测到码 → 触发 onDecoded 回调 → 返回结果。切忌用 for 循环 + startPreview() + 主线程阻塞(如 wait())来“等待扫描完成”——这不仅违反 Android 主线程不可阻塞的原则,还会导致 ANR(Application Not Responding)甚至崩溃,因为 wait() 在未持有锁或非同步上下文中调用会抛出 IllegalMonitorStateException,而 UI 线程也不允许长时间挂起。
✅ 正确做法是:将扫描流程设计为状态机或递归式回调链。每次成功解码后,在 onDecoded 中决定是否启动下一次扫描。例如,需连续扫描 10 次,可维护一个计数器,并在回调中递增、判断、触发下一轮:
private int scanCount = 0;
private static final int TOTAL_SCANS = 10;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CodeScannerView scannerView = findViewById(R.id.scanner_view);
mCodeScanner = new CodeScanner(this, scannerView);
mCodeScanner.setDecodeCallback(result -> {
// 在主线程安全地处理结果
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "Scan #" + (scanCount + 1) + ": " + result.getText(),
Toast.LENGTH_SHORT).show();
});
// 更新计数并决定是否继续
scanCount++;
if (scanCount <p>? 关键要点说明:</p>
- 绝不阻塞主线程:startPreview() 是非阻塞的,它立即返回并开始后台解码;onDecoded 在后台线程触发,因此必须用 runOnUiThread() 更新 UI。
- 扫描控制权在回调内:onDecoded 是唯一可靠的“扫描完成”信号点,所有后续逻辑(如计数、重启、终止)都应在此处编写。
- 资源管理需谨慎:多次调用 startPreview() 不会导致泄漏,但应在任务结束时调用 mCodeScanner.releaseResources() 释放摄像头资源。
-
增强鲁棒性建议:
- 添加超时机制(例如 Handler.postDelayed() 在 N 秒无扫码时提示用户);
- 支持手动中断(如添加“停止扫描”按钮,调用 mCodeScanner.stopPreview());
- 对重复扫码同一码做去重(Set
缓存已扫结果)。
这种回调驱动的设计符合 Android 生命周期与事件模型,代码简洁、可维护性强,且天然支持异步并发安全——这才是现代 Android 扫码开发的推荐实践。











