You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用崩溃及二维码功能异常问题求助

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:13:17