无法捕获MLKit文档扫描器中的IllegalStateException问题排查
MLKit文档扫描器插件未拍摄退出时的异常处理问题
我正在开发一款Flutter插件mlkit_document_scanner,用于封装新版MLKit文档扫描器。当前遇到的问题是:当用户未拍摄任何图片就退出扫描器时,无法观测到对应的退出事件,同时会抛出IllegalStateException,且没有日志提示活动销毁或无结果返回。需要找到可靠的方法预判并处理这个异常。
启动扫描器的代码
// Construct document scanner val scanner = library.buildGmsDocumentScanner( maximumNumberOfPages = call.argument<Int>(ARGUMENT_NUMBER_OF_PAGES) ?: 1, galleryImportAllowed = call.argument<Boolean>(ARGUMENT_GALLERY_IMPORT_ALLOWED) ?: false, scannerMode = call.argument<Int>(ARGUMENT_SCANNER_MODE)?.let { val allowedScannerModes = listOf( GmsDocumentScannerOptions.SCANNER_MODE_FULL, GmsDocumentScannerOptions.SCANNER_MODE_BASE, GmsDocumentScannerOptions.SCANNER_MODE_BASE_WITH_FILTER ) if (allowedScannerModes.contains(it)) it else GmsDocumentScannerOptions.SCANNER_MODE_FULL } ?: GmsDocumentScannerOptions.SCANNER_MODE_FULL, resultMode = DocumentScannerResultMode.values()[call.argument<Int>( ARGUMENT_RESULT_MODE ) ?: 2], ) // Launch document scanner activity, and collect failure if it occurs activity?.let { scanner .getStartScanIntent(it) .addOnSuccessListener { intentSender -> Log.d(LOGGING_TAG, "Launching document scanner") documentScannerLauncher?.launch( IntentSenderRequest.Builder(intentSender).build() ) } .addOnFailureListener { exception -> Log.e(LOGGING_TAG, "MLKit threw exception:" + exception.message) result.error( ERROR_CODE_START_SCAN_INTENT_FAILURE, ERROR_MESSAGE_START_SCAN_INTENT_FAILURE, exception ) } }
处理活动返回结果的代码
fun handleActivityResult( data: Intent?, eventSinkJPEG: EventChannel.EventSink?, eventSinkPDF: EventChannel.EventSink? ) { val documentScanningResult = GmsDocumentScanningResult.fromActivityResultIntent(data) if (documentScanningResult == null) { Log.d(LOGGING_TAG, "NOTHING CAME BACK FROM THE SCAN!!!") return } documentScanningResult.also { result -> result.pages.let { if (it.isNullOrEmpty()) { Log.d(LOGGING_TAG, "null response (result.pages)") eventSinkJPEG?.success(null) } else { Log.d(LOGGING_TAG, "JPEG pages count ${it.size}") eventSinkJPEG?.success(it.map { page -> page.imageUri.toFile().readBytes() }) } } result.pdf.let { if (it != null && it.pageCount > 0) { Log.d(LOGGING_TAG, "PDF pages count ${it.pageCount}") eventSinkPDF?.success(it.uri.toFile().readBytes()) } else { Log.d(LOGGING_TAG, "null response (result.pdf)") eventSinkPDF?.success(null) } } } }
抛出的异常日志
E/GmsDocScanDelAct( 5777): Failed to handle scanning result E/GmsDocScanDelAct( 5777): java.lang.IllegalStateException: Failed to handle result E/GmsDocScanDelAct( 5777): at com.google.mlkit.vision.documentscanner.internal.zzg.run(com.google.android.gms:play-services-mlkit-document-scanner@@16.0.0-beta1:12) E/GmsDocScanDelAct( 5777): at android.os.Handler.handleCallback(Handler.java:938) E/GmsDocScanDelAct( 5777): at android.os.Handler.dispatchMessage(Handler.java:99) E/GmsDocScanDelAct( 5777): at android.os.Looper.loopOnce(Looper.java:210) E/GmsDocScanDelAct( 5777): at android.os.Looper.loop(Looper.java:299) E/GmsDocScanDelAct( 5777): at android.os.HandlerThread.run(HandlerThread.java:67)
解决方案思路
捕获ActivityResult的结果码
用户退出扫描器时,ActivityResultLauncher的回调会返回Activity.RESULT_CANCELED结果码,可先判断该状态再处理数据:val documentScannerLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode == Activity.RESULT_CANCELED) { // 通知Flutter端用户取消扫描 eventSinkJPEG?.success(null) eventSinkPDF?.success(null) return@registerForActivityResult } // 执行原有结果处理逻辑 handleActivityResult(result.data, eventSinkJPEG, eventSinkPDF) }为结果解析方法添加异常捕获
调用GmsDocumentScanningResult.fromActivityResultIntent(data)时可能抛出异常,直接用try-catch包裹并处理:fun handleActivityResult( data: Intent?, eventSinkJPEG: EventChannel.EventSink?, eventSinkPDF: EventChannel.EventSink? ) { val documentScanningResult = try { GmsDocumentScanningResult.fromActivityResultIntent(data) } catch (e: IllegalStateException) { Log.e(LOGGING_TAG, "Failed to parse scan result: ${e.message}") // 通知Flutter端扫描失败 eventSinkJPEG?.success(null) eventSinkPDF?.success(null) return } // 原有处理逻辑... }监听活动生命周期(备选)
绑定扫描器活动的生命周期,监听销毁事件并结合结果是否为空判断用户操作,但这种方式复杂度较高,前两种方法更直接高效。
内容的提问来源于stack exchange,提问作者sunderee
相关产品推荐
相关产品推荐

