BitmapFactory:无法解码流:java.io.FileNotFoundException:打开失败:Android Q 上的 EACCES(权限被拒绝)
Posted
技术标签:
【中文标题】BitmapFactory:无法解码流:java.io.FileNotFoundException:打开失败:Android Q 上的 EACCES(权限被拒绝)【英文标题】:BitmapFactory: Unable to decode stream: java.io.FileNotFoundException:open failed: EACCES (Permission denied) on Android Q 【发布时间】:2020-05-17 11:37:18 【问题描述】:我授予了权限,但BitmapFactory.decodeFile()
返回此错误:
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20200130_165131.jpg: open failed: EACCES (Permission denied)
我想从图库中取出最后一张图片并将其保存到另一个文件中。我在运行它的 android P 测试设备上对其进行了测试。但它在具有 android 版本 Q(API 级别 29)的 android 模拟器中返回此错误。这有什么问题?
这些是我的代码 sn-ps:
writeStoragePermissionGranted();
BitmapFactory.Options options = null;
Bitmap bm = null;
String[] projection = new String[]
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.MIME_TYPE,
MediaStore.Images.ImageColumns.DISPLAY_NAME,
;
final Cursor cursor = this.getContentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor.moveToFirst())
final ImageView imageView = (ImageView) findViewById(R.id.pictureView);
String imageLocation = cursor.getString(1);
File imageFile = new File(imageLocation);
if (imageFile.exists())
options = new BitmapFactory.Options();
options.inSampleSize = 2;
try
bm = BitmapFactory.decodeFile(imageLocation, options);
catch(Exception e)
e.printStackTrace();
imageView.setImageBitmap(bm);
try
saveImage(bm,"NAME" );
catch (IOException e)
e.printStackTrace();
writeStoragePermissionGranted()
函数:
public void writeStoragePermissionGranted()
if (Build.VERSION.SDK_INT >= 23)
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED)
startPeriodicRequest();
else
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE, Constants.REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
else
return;
和清单权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我知道对此有很多问题。但是没有人在 android 模拟器版本 Q 上工作。另一方面,此代码适用于 android pie(API 级别 28)
【问题讨论】:
在 Android Q 上,该路径不再可达。不要使用 DATA 而是使用 RELATIVE_PATH。 @blackapps 你能解释的更清楚点吗?也许举个例子? 【参考方案1】:将android:requestLegacyExternalStorage="true"
添加到清单的应用程序块实际上可以解决问题!
【讨论】:
谢谢这解决了我的问题,简单又干净 谢谢,它节省了我的时间... +1 从我身边 这是更多用例的链接developer.android.com/training/data-storage#scoped-storage您可能需要它 requestLegacyExternalStorage 是一个临时修复。面向 Android 11 的应用将忽略此属性。它旨在让开发人员有时间迁移到更新的实现 在 targetsdk 30 requestLegacyExternalStorage 将忽略。你更新了吗?【参考方案2】:在 Android 10 上,他们引入了“Scoped Storage”的概念,这样,您就不能再使用其路径打开图像了。您可以获取更多信息HERE。
所以现在你必须使用它的ParcelFileDescriptor
和它的Uri
对其进行解码。
你可以:
final Cursor cursor = this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor.moveToFirst())
final ImageView imageView = (ImageView) findViewById(R.id.pictureView);
if (Build.VERSION.SDK_INT >= 29)
// You can replace '0' by 'cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)'
// Note that now, you read the column '_ID' and not the column 'DATA'
Uri imageUri= ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getInt(0));
// now that you have the media URI, you can decode it to a bitmap
try (ParcelFileDescriptor pfd = this.getContentResolver().openFileDescriptor(mediaUri, "r"))
if (pfd != null)
bitmap = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
catch (IOException ex)
else
// Repeat the code you already are using
【讨论】:
您好,使用此代码,如何将文件复制到某处以进行进一步处理?【参考方案3】:您只需要在Manifest.xml
中将android:requestLegacyExternalStorage="true"
添加到Application
标签即可。
希望下面的代码对你有所帮助。
Manifest.xml
在清单文件中添加以下内容:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
另加:
将此添加到 Manifest 的 Application 标记中。
android:requestLegacyExternalStorage="true"
打开图库获取图片:
private void openImagePicker()
MyDatePicker datePicker = new MyDatePicker();
datePicker.show(getSupportFragmentManager(), "DATE PICK");
启动 ActivityForResult:
onActivityResult
你会得到结果对象,你会得到图像原始uri。
ActivityResultLauncher<Intent> galleryResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>()
@Override
public void onActivityResult(ActivityResult result)
if (result.getResultCode() == Activity.RESULT_OK)
Intent data = result.getData();
imageURi = data.getData();
image.setVisibility(View.VISIBLE);
String path = getPath(imageURi);
File file = new File(path);
if (file.exists())
Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
image.setImageBitmap(myBitmap);
);
获取图片的绝对路径:
public String getPath(Uri uri)
String[] projection = MediaStore.Images.Media.DATA;
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null)
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
else return null;
【讨论】:
以上是关于BitmapFactory:无法解码流:java.io.FileNotFoundException:打开失败:Android Q 上的 EACCES(权限被拒绝)的主要内容,如果未能解决你的问题,请参考以下文章
BitmapFactory:无法解码流:java.io.FileNotFoundException:打开失败:Android Q 上的 EACCES(权限被拒绝)
BitmapFactory.decodeStream返回null的 ,InputStream 被调用两次,第一次调用流被关闭清空了!!!