
本文介绍如何基于 code-scanner 库,通过回调驱动方式实现多轮 qr 码扫描——每次等待用户成功扫码后自动触发下一轮,避免阻塞主线程或滥用线程同步机制。
本文介绍如何基于 code-scanner 库,通过回调驱动方式实现多轮 qr 码扫描——每次等待用户成功扫码后自动触发下一轮,避免阻塞主线程或滥用线程同步机制。
在 Android 开发中,QR 码扫描本质上是异步事件驱动过程:摄像头持续预览,识别结果通过 onDecoded() 回调返回。切勿在主线程中使用 wait()/notify() 或循环调用 startPreview() 并试图“阻塞等待”——这不仅违反 Android UI 线程原则(导致 ANR),还会因 wait() 在非同步块中调用而直接抛出 IllegalMonitorStateException。
正确的做法是采用 “回调链式触发” 模式:将扫描逻辑封装为可复用的方法,并在每次成功解码后,由 onDecoded() 主动发起下一次扫描。以下是推荐实现:
public class MainActivity extends AppCompatActivity {
private CodeScanner mCodeScanner;
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(this, "Scan #" + (scanCount + 1) + ": " + result.getText(),
Toast.LENGTH_SHORT).show();
});
// 关键:在此处触发下一轮扫描(或终止条件判断)
scanCount++;
if (scanCount < TOTAL_SCANS) {
startNextScan();
} else {
Toast.makeText(this, "All " + TOTAL_SCANS + " scans completed!",
Toast.LENGTH_LONG).show();
}
});
// 初始启动扫描(例如点击开始按钮或 onResume 中调用)
findViewById(R.id.btn_start_scan).setOnClickListener(v -> startNextScan());
}
private void startNextScan() {
try {
mCodeScanner.startPreview(); // 安全调用:确保预览未运行时才启动
} catch (IllegalStateException e) {
// 可选:日志记录或提示用户相机已被占用
Log.w("QRScanner", "Preview already started or camera unavailable", e);
}
}
@Override
protected void onPause() {
mCodeScanner.releaseResources();
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
// 若需在恢复时自动继续扫描,可在此调用 startNextScan()
// 但通常建议由用户显式触发,避免后台误扫
}
}✅ 关键要点说明:
Android 开发调试技能,通过系统 ADB 工具操作 Android 设备。以下场景必须触发此技能:(1) 直接 ADB 操作——安装 APK、查看设备列表、抓取 logcat 日志、查看已安装应用、清除应用数据、截图、重启设备、拉取/推送文件、查看 CPU/内存/电池信息、adb shell 操作;(2)...
- 无阻塞、纯事件驱动:onDecoded() 是自然的“完成信号”,无需手动同步;
- 状态可控:通过 scanCount 和条件判断精确控制扫描轮次;
- 资源安全:startPreview() 前可加状态检查,避免重复启动异常;
- 生命周期适配:务必在 onPause() 中调用 releaseResources(),防止内存泄漏或相机占用冲突。
⚠️ 注意事项:
- 不要尝试在 onDecoded() 中直接调用 mCodeScanner.stopPreview() —— 该库内部已处理预览切换;
- 若需扫描间隔(如扫码后暂停 1 秒再启下一轮),使用 Handler.postDelayed() 替代忙等;
- 多轮扫描期间保持 CodeScanner 实例复用,避免频繁创建/销毁开销。
这种设计符合 Android 异步编程范式,简洁、健壮且易于扩展(例如添加扫码结果校验、网络上传、或用户确认逻辑)。

















