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

调用uri.getLastPathSegment()时Android应用崩溃问题求助

问题分析与解决方案

兄弟,你的应用崩溃的核心原因很明确:使用MediaStore.ACTION_IMAGE_CAPTURE拍照后,直接调用data.getData()获取Uri是错误的——这个Intent默认只会把缩略图的Bitmap存在data的 extras 里,getData()返回的是null,后续调用uri.getLastPathSegment()自然就触发NullPointerException导致崩溃了!

下面给你两种针对性的解决方案,根据你的需求选择:

方案一:仅需要缩略图(快速实现)

如果你的场景只需要展示小尺寸的缩略图,不需要完整照片,可以直接从Intent的 extras 里取出Bitmap:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
        // 直接获取相机返回的缩略图Bitmap
        Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
        imageView.setImageBitmap(thumbnail);
        
        // 如果要上传缩略图,需要先把Bitmap转成文件,这里给你个简单示例:
        // File tempFile = new File(getExternalCacheDir(), "temp_thumb.jpg");
        // try (FileOutputStream fos = new FileOutputStream(tempFile)) {
        //     thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, fos);
        // } catch (IOException e) {
        //     e.printStackTrace();
        // }
        // 然后用tempFile的Uri去上传即可
    }
}

方案二:获取完整尺寸照片(推荐)

如果需要高清的完整照片,必须提前指定一个文件路径让相机把照片保存到该位置,而不是依赖系统返回的Uri。具体步骤如下:

1. 添加成员变量保存照片Uri

在MainActivity里新增一个成员变量:

private Uri photoUri;

2. 修改相机启动逻辑,指定输出文件

替换原来的按钮点击事件代码:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 先检查权限(Android 6.0+需要动态申请)
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    100);
            return;
        }

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File photoFile = null;
        try {
            // 创建临时文件存储照片
            photoFile = createImageFile();
        } catch (IOException ex) {
            Toast.makeText(MainActivity.this, "创建照片文件失败", Toast.LENGTH_SHORT).show();
            return;
        }
        if (photoFile != null) {
            // 根据Android版本获取文件Uri(7.0+必须用FileProvider)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                photoUri = FileProvider.getUriForFile(MainActivity.this,
                        "com.yourpackage.name.fileprovider", // 替换成你的应用包名+fileprovider
                        photoFile);
            } else {
                photoUri = Uri.fromFile(photoFile);
            }
            // 告诉相机把照片保存到指定Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
            startActivityForResult(intent, CAMERA_REQUEST_CODE);
        }
    }
});

3. 添加创建临时文件的方法

在MainActivity里新增这个方法:

private File createImageFile() throws IOException {
    // 生成唯一文件名,避免重复
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    // 用应用私有目录存储,不需要额外权限(Android 10+推荐)
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName, ".jpg", storageDir);
}

4. 配置FileProvider(针对Android 7.0+)

这一步是为了避免FileUriExposedException:

  • 在AndroidManifest.xml的<application>标签内添加Provider配置:
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.yourpackage.name.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">
    <!-- 指定应用私有Pictures目录为共享路径 -->
    <external-files-path name="my_images" path="Pictures" />
</paths>

5. 修改onActivityResult方法,使用提前保存的Uri

现在可以直接用我们之前生成的photoUri来上传图片了:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
        progress.setMessage("Uploading Image...");
        progress.show();
        
        StorageReference filePath = mStorage.child("Photos").child(photoUri.getLastPathSegment());
        filePath.putFile(photoUri)
                .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                    @Override
                    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                        progress.dismiss();
                        Toast.makeText(MainActivity.this, "Uploading Finished...", Toast.LENGTH_SHORT).show();
                        // 可选:把照片加载到ImageView显示
                        Glide.with(MainActivity.this).load(photoUri).into(imageView);
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        progress.dismiss();
                        Toast.makeText(MainActivity.this, "上传失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
}

最后别忘了添加权限

在AndroidManifest.xml里声明必要权限:

<uses-permission android:name="android.permission.CAMERA" />
<!-- Android 10+不需要WRITE_EXTERNAL_STORAGE,因为我们用的是应用私有目录 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:51:55