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

Google ML Kit二维码扫描Play Store版本空指针崩溃求助

CameraX二维码扫描发布版本崩溃:NullPointerException(Display为null)

问题场景

使用Google ML Kit+CameraX实现二维码扫描功能,调试阶段运行正常,但发布至Play Store后,部分机型出现崩溃,报错信息:

java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.Display.getRotation()' on a null object reference

定位到崩溃触发点为binding.previewView!!.display.rotation调用,该问题仅在发布版本中出现。

原因分析

发布版本默认开启R8/ProGuard代码优化,加上部分机型的View生命周期执行时机差异,导致bindPreviewUseCase方法执行时,PreviewView还未附加到Window上,此时display属性为null。调试模式无代码优化,View初始化时机刚好能避开这个问题。

解决方案

1. 替换Rotation获取方式

不要依赖PreviewView的display属性,改用Activity的WindowManager获取默认Display的rotation,更可靠:

private fun bindPreviewUseCase() {
    cameraProvider ?: return
    previewUseCase?.let { cameraProvider!!.unbind(it) }

    // 从Activity的WindowManager获取rotation,避免PreviewView未attach导致的null
    val displayRotation = windowManager.defaultDisplay.rotation

    previewUseCase = Preview.Builder()
        .setTargetAspectRatio(screenAspectRatio)
        .setTargetRotation(displayRotation)
        .build()
    previewUseCase?.setSurfaceProvider(binding.previewView.surfaceProvider)

    try {
        cameraProvider?.bindToLifecycle(
            this,
            cameraSelector!!,
            previewUseCase
        )
    } catch (e: IllegalStateException) {
        Log.e(TAG, "绑定预览用例失败: ${e.message}")
    } catch (e: IllegalArgumentException) {
        Log.e(TAG, "绑定预览用例参数错误: ${e.message}")
    }
}

2. 延迟绑定Camera用例

确保PreviewView附加到Window后再执行绑定操作,可通过监听View的attach状态实现:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityBarcodeScannerBinding.inflate(layoutInflater)
    setContentView(binding.root)

    // 监听PreviewView的attach状态
    binding.previewView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
        override fun onViewAttachedToWindow(v: View) {
            // View已附加到Window,再初始化相机
            setupCamera()
        }

        override fun onViewDetachedFromWindow(v: View) {
            // View脱离Window,解绑相机用例
            cameraProvider?.unbind(previewUseCase, analysisUseCase)
        }
    })
}

3. 避免强制非空断言

用安全调用+默认值替代!!强制非空,降低空指针风险:

// 替代原有的binding.previewView!!.display.rotation
val displayRotation = binding.previewView.display?.rotation ?: Surface.ROTATION_0

内容的提问来源于stack exchange,提问作者meazuri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:47:40