Android应用拍摄8-10张照片后崩溃问题求助
问题分析
从报错日志和代码来看,崩溃的直接原因是MediaStore.Images.Media.insertImage()方法返回了null,导致后续Uri.parse(path)抛出NullPointerException。而多次拍照后触发该问题,是因为这个方法已被官方废弃,且依赖系统MediaStore的插入逻辑,当图库中照片数量达到一定阈值时,会因存储配额、重复条目限制或系统兼容性问题返回空值。
同时当前拍照逻辑存在两个缺陷:
- 启动相机时将
EXTRA_OUTPUT设为null,导致相机仅返回低分辨率缩略图,而非原图 - 依赖废弃的
insertImage方法将Bitmap插入MediaStore,可靠性极低
解决方案
改用FileProvider指定相机拍照的保存路径,直接获取原图Uri,彻底规避MediaStore插入的不可靠操作:
1. 配置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="camera_images" path="Pictures" /> </paths>
2. 修改相机启动逻辑
替换原启动代码,生成临时文件并通过FileProvider获取可访问的Uri:
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File imageFile = null; try { // 生成唯一的临时图片文件 imageFile = File.createTempFile( "VISIT_", ".jpg", storageDir ); } catch (IOException e) { e.printStackTrace(); } if (imageFile != null) { // 获取FileProvider授权的Uri imageUri = FileProvider.getUriForFile( this, getPackageName() + ".fileprovider", imageFile ); Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 授予相机写入该Uri的权限 takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); }
3. 修改Activity结果回调
直接使用预先生成的imageUri,无需再处理返回的缩略图:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { if (imageUri != null) { String checkInOutText = checkInOut.getText().toString(); if ("Check In".equals(checkInOutText)) { checkInHolder.setVisibility(View.VISIBLE); checkInHolder.setImageURI(imageUri); } else if (checkInHolder.getVisibility() == View.VISIBLE && "Check Out".equals(checkInOutText)) { checkOutHolder.setVisibility(View.VISIBLE); checkOutHolder.setImageURI(imageUri); } // 上传数据库时,可直接通过该Uri获取文件流 } } }
4. 清理废弃代码
删除原有的getImageUri方法,因为不再需要将Bitmap插入MediaStore。
权限说明
- Android 10及以上:无需申请
WRITE_EXTERNAL_STORAGE权限,使用的是应用私有外部存储,系统自动授权 - Android 9及以下:需在Manifest中声明
WRITE_EXTERNAL_STORAGE权限,并在运行时请求该权限
内容的提问来源于stack exchange,提问作者Anthony Rafael
相关产品推荐
相关产品推荐

