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

使用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()自然就抛出空指针了。

解决方案:两种正确实现方式

方式一:先拍照,再启动裁剪(自定义相机流程)

这种方式适合需要完全控制相机启动逻辑的场景,步骤如下:

  1. 定义两个区分开的请求码,并声明变量保存拍照后的图片Uri:
private static final int REQUEST_CAMERA = 100;
private static final int REQUEST_CROP = 203;
private Uri capturedImageUri;
  1. 修改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);
}
  1. 修正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();
        }
    }
}
  1. 补充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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:10:41