使用Android-Image-Cropper库拍照后应用崩溃,报空指针异常求助
解决Android-Image-Cropper拍照后崩溃的空指针问题
问题根源分析
你遇到的空指针崩溃,核心原因是请求码和结果解析不匹配:
你启动的是系统相机的MediaStore.ACTION_IMAGE_CAPTURE Intent,却用了裁剪库的CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE作为请求码,后续又尝试用CropImage.getActivityResult(data)解析相机返回的结果——这个方法只能解析裁剪Activity返回的Intent,对相机返回的数据无法识别,所以得到的result是null,调用result.getUri()自然就抛出空指针了。
解决方案:两种正确实现方式
方式一:先拍照,再启动裁剪(自定义相机流程)
这种方式适合需要完全控制相机启动逻辑的场景,步骤如下:
- 定义两个区分开的请求码,并声明变量保存拍照后的图片Uri:
private static final int REQUEST_CAMERA = 100; private static final int REQUEST_CROP = 203; private Uri capturedImageUri;
- 修改
onCreate方法,启动相机时指定图片保存路径(避免Android 7.0+的Uri权限问题):
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_crop); Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 检查设备是否有相机应用 if (cameraIntent.resolveActivity(getPackageManager()) != null) { File imageFile = null; try { imageFile = createTempImageFile(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "创建图片文件失败", Toast.LENGTH_SHORT).show(); return; } if (imageFile != null) { // 用FileProvider生成安全Uri capturedImageUri = FileProvider.getUriForFile( this, "com.example.michael.matcalc.fileprovider", // 替换成你的App的FileProvider Authority imageFile ); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri); startActivityForResult(cameraIntent, REQUEST_CAMERA); } } } // 创建临时图片文件的工具方法 private File createTempImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String fileName = "CAMERA_" + timeStamp; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile(fileName, ".jpg", storageDir); }
- 修正
onActivityResult,分步骤处理相机和裁剪的返回结果:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 处理相机拍照完成的结果 if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) { // 启动裁剪Activity,传入拍照得到的图片Uri CropImage.activity(capturedImageUri) .setGuidelines(CropImageView.Guidelines.ON) // 显示裁剪网格线 .setAspectRatio(1, 1) // 自定义裁剪比例 .start(this); } // 处理裁剪完成的结果 else if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) { CropImage.ActivityResult result = CropImage.getActivityResult(data); if (resultCode == RESULT_OK) { ((ImageView) findViewById(R.id.quick_start_cropped_image)).setImageURI(result.getUri()); Toast.makeText(this, "裁剪成功,采样率:" + result.getSampleSize(), Toast.LENGTH_LONG).show(); } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) { Toast.makeText(this, "裁剪失败:" + result.getError(), Toast.LENGTH_LONG).show(); } } }
- 补充FileProvider配置(Android 7.0+必需):
在AndroidManifest.xml的<application>标签内添加:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.michael.matcalc.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
然后在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>
方式二:直接使用裁剪库的内置选择器(更简单)
裁剪库已经封装了拍照/选图库的逻辑,直接调用即可,无需自己处理相机Intent:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_crop); // 直接启动裁剪库的选择界面,支持拍照或从图库选图 CropImage.activity() .setGuidelines(CropImageView.Guidelines.ON) .setAspectRatio(1, 1) .start(this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) { CropImage.ActivityResult result = CropImage.getActivityResult(data); if (resultCode == RESULT_OK) { ((ImageView) findViewById(R.id.quick_start_cropped_image)).setImageURI(result.getUri()); Toast.makeText(this, "裁剪成功,采样率:" + result.getSampleSize(), Toast.LENGTH_LONG).show(); } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) { Toast.makeText(this, "裁剪失败:" + result.getError(), Toast.LENGTH_LONG).show(); } } }
内容的提问来源于stack exchange,提问作者Michael Helmbrecht
相关产品推荐
相关产品推荐

