如何在Android Q中删除我创建的文件?

4

我将一张图片保存在DCIM目录下,但是有时候需要删除它。以前我只是调用了image.delete(),其中image是文件。但现在这张图片被以另一种方式保存:

    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM" + File.separator + IMAGES_FOLDER_NAME);

    Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    OutputStream fos = resolver.openOutputStream(imageUri);
    boolean saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);

我试图通过文件名进行查询,并调用contentResolver.delete(...),但它没有起作用。
我有写外部存储的权限,但我不想使用SAF。
如何删除这样的文件?

你可以在清单文件中使用 android:requestLegacyStorage="true",并继续使用旧的 API。 - Darshan
@DarShan 你的意思是:android:requestLegacyExternalStorage="true" - t0m
4个回答

6
您需要使用ContentResolverdelete方法,使用您在调用insert时获取的Uri
 Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
 OutputStream fos = resolver.openOutputStream(imageUri);
 boolean saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
 ......
 int result = resolver.delete(imageUri, null, null);
 if (result > 0) {
     Log.d("Tag", "File deleted");
 }

如果您没有存储需要执行 query() 的 Uri,则需检索内容并调用 delete

对我来说,这不起作用,文件本身并没有被删除(我仍然可以在文件浏览器中看到它)。 - user3738870
@user3738870 你在使用Android Q吗?请查看我在这里发布的答案:https://dev59.com/LrXna4cB1Zd3GeqPMYYH#62362565 - K.Os
1
@K.Os 谢谢你的建议,但对我来说行不通,因为问题不是由于安全异常(该文件是由我的应用程序创建的,所以我不需要权限)。即使从“MediaStore”中删除了该文件,它仍然会留在那里。 - user3738870

1
完整的解决方案还应包括处理在尝试使用ContentResolver删除时可能发生的Android Q上的潜在错误。在这种情况下,您应该将代码包装在try/catch块中。 以下是解决方案:
      try {
        // 1
        getApplication<Application>().contentResolver.delete(
                imageUri,"${MediaStore.Images.Media._ID} = ?",
                arrayOf(imageId)
        )
      }
       // 2
      catch (securityException: SecurityException) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
          val recoverableSecurityException =
                  securityException as? RecoverableSecurityException
                          ?: throw securityException

             val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender
             startIntentSenderForResult(
                intentSender,
                DELETE_PERMISSION_REQUEST,
                null,
                0,
                0,
                0,
                null
              )
        } else {
          throw securityException
        }
      }
  1. 在这里,你在try块中调用contentResolver.delete()方法,因为该方法可能会在运行时抛出SecurityException异常。该方法需要要删除的图像的ContentUri。在where参数中,您指定要根据其_ID删除图像。在最后一个参数中,您将_ID的字符串版本传递给数组。

  2. 在Android 10及以上版本中,无法直接从MediaStore中删除或修改项目。您需要获得这些操作的权限。正确的方法是首先捕获RecoverableSecurityException,其中包含一个intentSender,可以提示用户授予权限。然后,您使用从RecoverableSecurityException提取的intentSender启动startIntentSenderForResult以授予在Android Q上删除文件的附加权限。

来源: https://www.raywenderlich.com/9577211-scoped-storage-in-android-10-getting-started


1

在调用 startActivityForResult 方法之前,需要使用 intent.addFlags 方法。示例如下:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
          | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

因为它在ContentProvider#enforceWritePermissionInner中检查权限。

真正的实现在ActivityManagerService#checkPermission方法中。


0
  File file = new File(delPath);
  if (file.exists()) {
   try {
        Uri imageUri = FileProvider.getUriForFile(Context,
                        getApplicationContext()
                                .getPackageName() + ".provider", file);
        ContentResolver contentResolver = getContentResolver();
                int deletefile = contentResolver.delete(imageUri, null, null);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

这里的删除路径delPath是您想从存储中删除的图像文件路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接