1.【預測再驗證|平台能力】 新的掃描畫面用 CameraX 的 ImageAnalysis 餵影格給 ML Kit 的條碼辨識,骨架大概是這樣:
val analysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
val scanner = BarcodeScanning.getClient(
BarcodeScannerOptions.Builder()
.setBarcodeFormats(Barcode.FORMAT_CODE_128, Barcode.FORMAT_QR_CODE)
.build(),
)
analysis.setAnalyzer(executor) { imageProxy ->
val image = InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees)
scanner.process(image)
.addOnSuccessListener { barcodes -> onBarcodes(barcodes.map { it.rawValue }) }
.addOnCompleteListener { imageProxy.close() }
}
下面每個情境,先寫下你的預測,再拿實機(印幾張 Code 128 與 QR Code)或 instrumented test 驗證:
onBarcodes 被呼叫幾次?每次的清單裡有幾筆?如果呼叫端把每次呼叫都當成「掃到一個新條碼」,畫面上的清單會長成什麼樣?你打算在哪一層去重:analyzer、掃描畫面的 ViewModel,還是呼叫端?去重的依據是「值相同」還是「值相同且在 N 秒內」?rotationDegrees 固定傳 0,手機直拿掃一張橫向印的 Code 128,再掃一張 QR Code。哪一種還掃得到?為什麼兩種不一樣?imageProxy.close() 那行拿掉。預覽畫面會怎樣?onBarcodes 還會被呼叫嗎?幾次之後停?setBarcodeFormats 拿掉改成辨識全部格式。同一張條碼從進畫面到第一次回傳的時間差多少?用 System.nanoTime() 量十次取中位數。差距值得為此把格式寫進設定嗎?最後回答:這五個情境裡,哪幾個可以用 instrumented test 餵固定圖片(InputImage.fromBitmap)穩定重現?哪幾個只能在實機驗、而且要寫進發版前的手動檢查清單?
我的回答:(待補)
2.【決策邊界|架構論述】 舊 App 有 13 個掃描 Activity,每個大約一千行、九成五相同:相機與辨識、閃光燈開關、掃到的條碼堆成一個列表、「清除」與「關閉」鈕、關閉時把列表當結果回傳。不同的是那 5%:有的掃一個就結束、有的連續掃;有的每掃到一筆就立刻呼叫後端驗證這筆能不能收,後端拒絕就跳對話框、震動、不加進列表;有的接受掃到的條碼比業務編號長、只取前面固定長度的那段;有的要帶上「這次是為哪個客戶、哪種任務掃的」。
新設計要收成一個 ScannerScreen,差異由 ScanConfig 描述、結果用 ScanResult 交回。請寫下:
ScanConfig 裡放什麼、不放什麼?至少判斷這幾項各歸哪邊(設定資料、呼叫端的回呼、還是乾脆不屬於掃描畫面):接受的條碼格式;單次或連續;去重規則;掃到的值要不要照業務規則修剪或檢查長度;每掃一筆就向後端驗證並決定收不收;驗證失敗時的提示文字;預設開不開閃光燈;「為哪個客戶掃」這類只有呼叫端在乎的上下文。ScanConfig 帶一個 suspend (String) -> Verdict 的驗證函式,由掃描畫面呼叫並顯示結果;(C) 不做通用畫面,改成提供「相機預覽+辨識」的可組合元件,13 種流程各自組自己的畫面。每種做法在這幾個條件下會怎樣:驗證要打網路而手機離線;驗證要兩秒而使用者已經把鏡頭移到下一個條碼;之後要新增第 14 種流程;要為掃描畫面寫單元測試。你預設選哪一個,什麼條件下改選別的?core:scanner、data 的 mapper,還是呼叫端的 ViewModel?寫下你的理由,以及這個決定對第 1 題「去重的依據」有什麼影響。ScannerScreen 的一部分(同一個畫面切換模式),還是呼叫端自己的另一個輸入框?兩種做法下 ScanResult 要不要區分「掃的」和「打的」?結果怎麼從掃描畫面回到呼叫端(SavedStateHandle 還是共享 ViewModel)是明天 Day 25 的題目,今天不用答。
我的回答:(待補)