Android相机Intent的onActivityResult()返回Null错误技术问询
嘿,我遇到过一模一样的问题!这大概率是因为部分安卓厂商的相机应用没有遵循标准的Intent返回规则,导致onActivityResult里的data直接为null。我给你两个解决方案,亲测有效~
问题分析
按照Android官网的示例,ACTION_IMAGE_CAPTURE应该会把缩略图放到Intent的extras中,但不少第三方相机App(甚至部分原生相机)为了性能或者自身逻辑,不会返回这个缩略图数据,直接让data变成null。此外,Android 10及以上的Scoped Storage限制也可能间接导致这个问题。
先补全你可能的onActivityResult代码(方便对照):
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { // 这里data可能为null,导致getExtras()抛出空指针 Bundle extras = data.getExtras(); Bitmap imageBitmap = (Bitmap) extras.get("data"); ImageView imageView = findViewById(R.id.imageView); imageView.setImageBitmap(imageBitmap); } }
解决方案一:指定输出文件(最可靠)
这个方法不依赖相机返回的data,而是提前指定一个文件让相机保存原图,之后我们自己从文件生成缩略图,兼容性拉满。
步骤1:添加权限(AndroidManifest.xml)
<!-- Android 10+ 不需要WRITE_EXTERNAL_STORAGE,除非要存到公共目录 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <uses-feature android:name="android.hardware.camera" android:required="false"/>
步骤2:实现创建临时文件的方法
private File createImageFile() throws IOException { // 生成唯一文件名,避免重复 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; // 用应用私有目录,不需要额外权限 File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile( imageFileName, // 文件名前缀 ".jpg", // 文件后缀 storageDir // 存储目录 ); }
步骤3:修改拍照Intent,指定输出路径
static final int REQUEST_IMAGE_CAPTURE = 1; private String currentPhotoPath; // 保存当前照片的路径 private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // 处理文件创建失败的情况,比如弹Toast提示 ex.printStackTrace(); Toast.makeText(this, "创建图片文件失败", Toast.LENGTH_SHORT).show(); } if (photoFile != null) { // 用FileProvider生成Uri,避免Android 7+的FileUriExposedException Uri photoURI = FileProvider.getUriForFile(this, "com.yourapp.package.fileprovider", // 替换成你的APP包名+fileprovider photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); currentPhotoPath = photoFile.getAbsolutePath(); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } }
步骤4:配置FileProvider(AndroidManifest.xml)
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="com.yourapp.package.fileprovider" <!-- 和上面的authority一致 --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... </application>
步骤5:创建file_paths.xml文件(res/xml目录下)
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应我们之前用的getExternalFilesDir(Environment.DIRECTORY_PICTURES) --> <external-files-path name="my_images" path="Pictures" /> </paths>
步骤6:修改onActivityResult读取文件生成缩略图
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { // 从指定文件读取原图,再生成合适大小的缩略图 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; // 缩小4倍,可根据需求调整 Bitmap imageBitmap = BitmapFactory.decodeFile(currentPhotoPath, options); ImageView imageView = findViewById(R.id.imageView); imageView.setImageBitmap(imageBitmap); } }
解决方案二:兼容处理data为null的情况
如果你不想改太多代码,可以先判断data是否为null,再做分支处理:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { Bitmap imageBitmap = null; // 先尝试从Intent获取缩略图 if (data != null && data.getExtras() != null) { imageBitmap = (Bitmap) data.getExtras().get("data"); } // 如果失败,再尝试从指定文件读取(前提是你用了方案一的文件保存逻辑) else if (currentPhotoPath != null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; imageBitmap = BitmapFactory.decodeFile(currentPhotoPath, options); } if (imageBitmap != null) { ImageView imageView = findViewById(R.id.imageView); imageView.setImageBitmap(imageBitmap); } else { Toast.makeText(this, "无法获取图片,请重试", Toast.LENGTH_SHORT).show(); } } }
总结
方案一是最推荐的,因为它不依赖相机应用的实现,不管什么厂商的相机都能正常工作。方案二适合快速兼容,但还是可能遇到部分设备无法获取的情况。
内容的提问来源于stack exchange,提问作者Mr.Drew
相关产品推荐
相关产品推荐

