权限拒绝:MediaDocumentsProvider

尝试显示URI时,我收到以下exception。 我认为它发生在我的活动停止后,我尝试再次访问一个可行的URI。 还有其他问题可以解决这个问题,但我对如何将任何解决方案应用于我的代码感到很困惑,因为我的takePhotoIntent允许从图库中获取或选择图片(见下文)。

Unable to open content: content://com.android.providers.media.documents/document/image%3A49688 java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image%3A49688 from pid=821, uid=10238 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission() 

我的createImageFile和我的takePhotoIntent:

 private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); // Save a file: path for use with ACTION_VIEW intents mCurrentPhotoPath = "file:" + image.getAbsolutePath(); return image; } private void dispatchTakePictureIntent() { for(int i = 0; i < 4; i++) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); outputFileUri = Uri.fromFile(photoFile); } catch (IOException ex) { Log.w("error","IOException"); }catch (NullPointerException nullEx) { Log.w("error","NullPointerException"); } // Camera. final List cameraIntents = new ArrayList(); final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); final PackageManager packageManager = getPackageManager(); final List listCam = packageManager.queryIntentActivities(captureIntent, 0); for (ResolveInfo res : listCam) { final String packageName = res.activityInfo.packageName; final Intent intent = new Intent(captureIntent); intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); intent.setPackage(packageName); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); cameraIntents.add(intent); } // Filesystem. final Intent galleryIntent = new Intent(); galleryIntent.setType("image/*"); galleryIntent.setAction(Intent.ACTION_GET_CONTENT); // Chooser of filesystem options. final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source"); // Add the camera options. chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[cameraIntents.size()])); if(id.equals(HAPPY_ID)) startActivityForResult(chooserIntent, REQUEST_HAPPY_PHOTO); if(id.equals(SURPRISED_ID)) startActivityForResult(chooserIntent, REQUEST_SURPRISED_PHOTO); if(id.equals(AFRAID_ID)) startActivityForResult(chooserIntent, REQUEST_AFRAID_PHOTO); if(id.equals(UPSET_ID)) startActivityForResult(chooserIntent, REQUEST_UPSET_PHOTO); if(id.equals(SAD_ID)) startActivityForResult(chooserIntent, REQUEST_SAD_PHOTO); } } } 

根据Storage Access Framework客户端文档 :

  • 如果您希望应用程序只是读取/导入数据,请使用ACTION_GET_CONTENT 。 使用此方法,应用程序将导入数据的副本,例如图像文件。

  • 如果您希望应用程序对文档提供程序拥有的文档具有长期,持久的访问权限,请使用ACTION_OPEN_DOCUMENT 。 一个例子是照片编辑应用程序,它允许用户编辑存储在文档提供程序中的图像。

当您使用ACTION_GET_CONTENT ,您对Uri的访问在组件被销毁时结束(除非您将Uri传递给新组件)。 如果您希望在组件的生命周期之后继续访问该文件,则必须从Uri复制该文件,或者切换到ACTION_OPEN_DOCUMENT并保留权限 (仅限文档Uris)。