Android应用崩溃及二维码功能异常问题求助
我来帮你一步步解决这个Android二维码扫描应用的崩溃和功能异常问题,针对你排查到的三个代码问题,我会给出具体的修复方案,同时解决扫描结果不显示的核心问题:
一、修复图库选择图片崩溃(类型不匹配错误)
你遇到的崩溃根源是data?.data是可空类型Uri?,但InputImage.fromFilePath要求传入非空的Uri,直接传空值会触发空指针异常。我们需要先做空安全判断:
galleryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult(), object : ActivityResultCallback<ActivityResult> { override fun onActivityResult(result: ActivityResult?) { val data = result?.data val imageUri = data?.data ?: return // 若Uri为空则直接终止方法,避免崩溃 inputImage = InputImage.fromFilePath(requireContext(), imageUri) processQr() } })
说明:用?: return实现空安全处理,只有当Uri有效时才执行后续的二维码解析逻辑,从根源避免空指针崩溃。
二、简化冗余的SAM构造函数
Kotlin支持SAM转换,可以去掉冗余的DialogInterface.OnClickListener显式构造,用lambda表达式简化代码:
binding.btnScanBarcode.setOnClickListener { val options = arrayOf("camera", "gallery") AlertDialog.Builder(requireContext()) .setTitle("Pick an option") .setItems(options) { dialog, which -> when(which) { 0 -> { val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) cameraLauncher.launch(cameraIntent) } 1 -> { val storageIntent = Intent(Intent.ACTION_GET_CONTENT).apply { type = "image/*" } galleryLauncher.launch(storageIntent) } } } .show() }
说明:用lambda替代SAM构造函数,同时用when替代if-else让分支逻辑更清晰,代码更简洁易读。
三、替换已废弃的权限请求方法
onRequestPermissionsResult已被官方标记为废弃,推荐使用Jetpack的ActivityResultContracts.RequestMultiplePermissions来处理权限请求,这是更现代、更简洁的方式:
1. 定义权限请求Launcher
private val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false val readStorageGranted = permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false val writeStorageGranted = permissions[Manifest.permission.WRITE_EXTERNAL_STORAGE] ?: false when { cameraGranted && readStorageGranted && writeStorageGranted -> { // 所有权限授予完成,可执行扫描/图库操作 } !cameraGranted -> { Toast.makeText(requireContext(), "Camera Permission Denied", Toast.LENGTH_SHORT).show() } !readStorageGranted || !writeStorageGranted -> { Toast.makeText(requireContext(), "Storage Permission Denied", Toast.LENGTH_SHORT).show() } } }
2. 发起权限请求
// 在需要请求权限的地方调用(比如点击扫描按钮时) permissionLauncher.launch( arrayOf( Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ) )
说明:这种方式可以一次性请求多个权限,无需手动管理请求码,回调中直接获取每个权限的授予状态,完全符合Android最新开发规范。
四、修复相机扫描结果不显示问题
扫描结果无法显示到tvResult,通常是因为二维码解析的回调在子线程,直接更新UI会触发异常。需要切换到主线程更新控件:
private fun processQr() { val recognizer = BarcodeScanning.getClient() recognizer.process(inputImage) .addOnSuccessListener { barcodes -> val scanResult = barcodes.firstOrNull()?.rawValue ?: "No QR code detected" // 切换到主线程更新UI requireActivity().runOnUiThread { binding.tvResult.text = scanResult } } .addOnFailureListener { error -> requireActivity().runOnUiThread { binding.tvResult.text = "Scan failed: ${error.message}" } } }
说明:Google ML Kit的扫描回调运行在子线程,必须通过runOnUiThread切换到主线程才能安全更新TextView的内容,确保扫描结果正常显示。
内容的提问来源于stack exchange,提问作者Low Jung Xuan

