调用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
相关产品推荐
相关产品推荐

