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

Android 11设备(三星机型为主)使用Camera Intent横屏拍照返回后崩溃问题

解决Android 11(三星设备)横屏拍照后崩溃的NPE问题

根据你描述的情况,这个崩溃的核心原因是横竖屏切换导致Fragment重建,之前存储的拍照目标文件路径丢失,加上Android 11(尤其是三星定制系统)对相机Intent返回结果的处理细节变化,最终在onActivityResult中调用new File()时传入了null值,触发NullPointerException。

下面是针对性的解决方案,完全适配Android 11+,同时兼容低版本:

1. 用ViewModel保存拍照文件对象(避免配置变更丢失)

横竖屏切换会触发Fragment/Activity重建,原来的实例变量会被重置。我们可以用ViewModel来持久化拍照的临时文件对象,确保重建后依然能获取到:

步骤1:创建CameraViewModel

import androidx.lifecycle.ViewModel
import java.io.File

class CameraViewModel : ViewModel() {
    var photoFile: File? = null
}

步骤2:在Fragment中关联ViewModel

import androidx.fragment.app.viewModels

private val cameraViewModel by viewModels<CameraViewModel>()

2. 重构拍照文件创建逻辑

按照官方文档的方式创建临时文件,但把文件对象存入ViewModel,而不是局部/实例变量:

import android.os.Environment
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*

private fun createImageFile(): File {
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    
    return File.createTempFile(
        "JPEG_${timeStamp}_",
        ".jpg",
        storageDir
    ).apply {
        // 将文件对象存入ViewModel
        cameraViewModel.photoFile = this
    }
}

3. 启动相机Intent(使用FileProvider)

确保用FileProvider生成Uri,适配Android 7+的文件权限要求:

import android.content.Intent
import android.provider.MediaStore
import androidx.core.content.FileProvider

private const val REQUEST_IMAGE_CAPTURE = 65660

private fun dispatchTakePictureIntent() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        takePictureIntent.resolveActivity(requireContext().packageManager)?.also {
            val photoFile = try {
                createImageFile()
            } catch (ex: IOException) {
                // 处理文件创建失败的情况
                null
            }
            
            photoFile?.also {
                val photoURI = FileProvider.getUriForFile(
                    requireContext(),
                    "${requireContext().packageName}.fileprovider",
                    it
                )
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
            }
        }
    }
}

4. 修复onActivityResult的空值判断

从ViewModel中获取文件对象,避免空指针:

import android.app.Activity
import android.graphics.BitmapFactory
import android.widget.Toast

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
        // 优先从ViewModel获取文件,避免重建后为空
        val photoFile = cameraViewModel.photoFile ?: run {
            Toast.makeText(requireContext(), "无法加载拍摄的图片", Toast.LENGTH_SHORT).show()
            return
        }
        
        // 将图片加载到ImageView
        val imageBitmap = BitmapFactory.decodeFile(photoFile.absolutePath)
        yourImageViewId.setImageBitmap(imageBitmap)
    }
}

5. 确保FileProvider配置正确

在AndroidManifest.xml中添加FileProvider声明:

<application>
    ...
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    ...
</application>

然后在res/xml/file_paths.xml中配置文件路径:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Pictures" />
</paths>

为什么这个方案能解决问题?

  • Android 11及三星设备横屏拍照时,相机应用会导致你的Fragment重建,原来的文件路径变量会被清空,而ViewModel不受配置变更影响,能保留文件引用。
  • 使用应用专属目录存储临时拍照文件,不需要额外的存储权限,规避了Android 11的存储访问限制。
  • 提前做空值判断,避免NullPointerException的触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:12:48