BitmapFactory:无法解码流:java.io.FileNotFoundException:打开失败:Android Q上的EACCES(权限被拒绝)

时间:2020-01-31 19:17:55

标签: java android android-10.0

我已授予权限,但是Object() or Object()返回此错误:

BitmapFactory.decodeFile()

我想从图库中获取最后一张图像,并将其保存到另一个文件中。我在运行它的Android P测试设备上对其进行了测试。但它会在具有Android版本Q(API级别29)的android模拟器中返回此错误。怎么了?

这些是我的代码段:

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20200130_165131.jpg: open failed: EACCES (Permission denied)

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;
    }
} 

我知道对此有很多疑问。但是没有人在Android模拟器版本Q上工作。另一方面,此代码在android pie(API级别28)上有效。

3 个答案:

答案 0 :(得分:21)

清单的应用程序块中添加android:requestLegacyExternalStorage="true"实际上可以解决该问题!

答案 1 :(得分:10)

在Android 10上,他们引入了“范围存储”的概念,这样一来,您将无法再使用其路径打开图像。您可以获取更多信息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
    }
}

答案 2 :(得分:0)

您只需将 android:requestLegacyExternalStorage="true" 添加到 Application 中的 Manifest.xml 标签。

希望下面的代码能帮到你。

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;
}