记录日期:2026-08-26
项目仓库:/Users/liang/AndroidStudioProjects/CusumptionMachine
实施分支:simplify_menu_pay
伟邦扫码原实现由每个页面或弹框直接打开物理串口并创建阻塞读取线程。业务关闭时仅调用 interrupt()、关闭串口和清空回调,设备驱动不能保证阻塞中的 InputStream.read() 立即退出。下一次重新打开伟邦扫码后,旧线程可能继续与新线程竞争二维码数据,造成扫码器响声正常但当前页面未收到付款码。
原实现还把一次串口 read() 当成一条完整二维码。数据未以 CRLF 结束时会直接丢弃,无法处理半包、粘包以及 CR、LF 分两次到达的情况。
WabonQrcodePortManager,作为伟邦扫码物理串口的唯一所有者,进程内只保留一个阻塞读取线程。/dev/ttyACM0,伟邦壁挂和卧式继续使用 /dev/ttyS3;设备协议地址和波特率集中在端口管理器中。WabonQrcodeSerialPortScanner 改为轻量业务会话,支持 resume()、pause() 和永久 close();页面关闭时只注销会话,不再关闭物理串口。LatestSessionDispatcher,扫码结果只投递给最后注册的有效会话;旧页面关闭和主线程排队的迟到结果不会影响当前页面。CrLfTextFrameDecoder,缓存未结束片段并按 CRLF 拆分完整二维码,支持半包、一次读取多帧、空帧过滤和分隔符拆分。onStart()/onStop() 配对。onStop() 兜底释放。app/src/main/java/com/cpt/cusumption/devices/serial/CrLfTextFrameDecoder.javaapp/src/main/java/com/cpt/cusumption/devices/wabon/WabonQrcodePortManager.javaapp/src/main/java/com/cpt/cusumption/devices/wabon/WabonQrcodeSerialPortScanner.javaapp/src/main/java/com/cpt/cusumption/activity/OrderVerifyActivity.javaapp/src/main/java/com/cpt/cusumption/activity/MealServedActivity.javaapp/src/main/java/com/cpt/cusumption/activity/NewQuotaActivity.javaapp/src/main/java/com/cpt/cusumption/view/WabonBigQrcodeScanPop.javaapp/src/test/java/com/cpt/cusumption/devices/serial/CrLfTextFrameDecoderTest.javaCrLfTextFrameDecoderTest,确认生产解码器缺失时测试编译失败。CrLfTextFrameDecoderTest 和 LatestSessionDispatcherTest:共 8 个测试全部通过。CrLfTextFrameDecoderTest 共 4 个测试,覆盖半包缓存、单次读取多帧、CRLF 跨读取拆分和空帧过滤。JAVA_HOME=/Users/liang/Library/Java/JavaVirtualMachines/corretto-1.8.0_482/Contents/Home bash gradlew :app:testDebugUnitTest :app:assembleDebug:BUILD SUCCESSFUL。app/build/outputs/apk/debug/app-debug.apk。a14a6b4da6f31bb9dfe6461a6e105ad055768b50e0dda1d32b2f84b962eace97。CRLF 分次到达,均应完整解析且每帧只回调一次。