15

我正在更新我的应用程序以使用 Android 10 中引入的 Scoped Storage 功能。

我的应用程序与 MediaStore 一起使用并显示图像、视频和音频文件,并为用户提供删除项目的能力。

我之前为删除文件所做的操作:

  1. 从那里得到路径MediaStore.MediaColumns.DATA
  2. 用于new File(path).delete()删除该文件
  3. 手动更新 MediaStore

现在 MediaStore.MediaColumns.DATA 不可用我迁移到使用ContentResolver.delete()从 MediaStore 中删除项目

例如,我有项目的 uri:(content://media/external/images/media/502它的有效 uri,我在网格中显示它的缩略图)。我是否在 MediaStore 或其他应用程序中插入了这个项目并不重要。

我用context.getContentResolver().delete(uri, null, null). 它要么成功删除(返回 1 行),要么捕获RecoverableSecurityException用于startIntentSenderForResult()访问当前 uri,然后使用相同的 uri 将getContentResolver().delete()其删除,onActivityResult()然后成功删除。

无论哪种方式,该项目都会从 MediaStore 中删除,并且在我查询 MediaStore 以获取图像时或在其他应用程序中都不会显示在结果中。

此文件存在于文件系统上(使用 SAF 和各种文件管理器(Google Files、Total Commander)检查)

有时(取决于 Android 版本和媒体类型)这些项目会在手机重新启动后(或打开 Google 相册后 - 它会扫描文件系统)带回 MediaStore

例如:我的 Google Pixel 和 Google Pixel 3a XL 上的 Android 10 的行为与上述图像/视频/音频的行为相同,但小米 Mi A2 Lite 上的 Android 9 仅对音频文件的行为如此,而删除图像/视频则很好。

我有android:requestLegacyExternalStorage="false"清单。

有没有办法强制 MediaStore 也删除文件系统上的数据?为什么文件系统上的文件被遗忘了?

4

5 回答 5

5

是的,正如您所指出的,这就是我们必须删除媒体文件的方式。我们必须通过形成一个 File 对象来删除文件的物理副本,并使用 ContentResolver.delete() 删除 MediaStore 中的索引文件(或)对已删除的文件进行媒体扫描,这将删除它在 MediaStore 中的条目。

这就是它过去在 Android 10 操作系统下的工作方式。如果您通过在清单 android:requestLegacyExternalStorage="true" 中指定范围存储来选择退出范围存储,那么在 Android 10 中仍然可以正常工作

现在在Android 11中,您被迫使用范围存储。如果您想删除任何不是您创建的媒体文件,您必须获得用户的许可。您可以使用 MediaStore.createDeleteRequest() 获取权限。这将显示一个对话框,描述用户将要执行的操作,一旦授予权限,android 有一个内部代码来负责删除物理文件和 MediaStore 中的条目。

private void requestDeletePermission(List<Uri> uriList){
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
      PendingIntent pi = MediaStore.createDeleteRequest(mActivity.getContentResolver(), uriList);

      try {
         startIntentSenderForResult(pi.getIntentSender(), REQUEST_PERM_DELETE, null, 0, 0,
                  0);
      } catch (SendIntentException e) { }
    }
}

上面的代码会同时执行这两种操作,请求删除权限,一旦授予权限,也可以删除文件。

你会在 onActivityResult() 中得到回调结果

于 2020-11-12T08:29:40.247 回答
3

使用此函数使用文件的显示名称删除文件: 此函数将删除 MediaStore 项目及其在 Android-10 或 Android-Q 文件系统上的关联数据

注意:就我而言,我正在使用 MediaStore.Files.FileColumns 之类的文件。

public static boolean deleteFileUsingDisplayName(Context context, String displayName) {

    Uri uri = getUriFromDisplayName(context, displayName);
    if (uri != null) {
        final ContentResolver resolver = context.getContentResolver();
        String[] selectionArgsPdf = new String[]{displayName};

        try {
            resolver.delete(uri, MediaStore.Files.FileColumns.DISPLAY_NAME + "=?", selectionArgsPdf);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            // show some alert message
        }
    }
    return false;

}

使用此函数从 DisplayName 获取 Uri

public static Uri getUriFromDisplayName(Context context, String displayName) {

    String[] projection;
    projection = new String[]{MediaStore.Files.FileColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = context.getContentResolver().query(extUri, projection,
            MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
    assert cursor != null;
    cursor.moveToFirst();

    if (cursor.getCount() > 0) {
        int columnIndex = cursor.getColumnIndex(projection[0]);
        long fileId = cursor.getLong(columnIndex);

        cursor.close();
        return Uri.parse(extUri.toString() + "/" + fileId);
    } else {
        return null;
    }

}
于 2020-08-24T04:38:04.670 回答
2

根据我的观察,没有强制删除。

如果文件真的在 Android Q 上被删除,我通常会添加几项检查,如果没有用户手动确认每个文件,也无法删除整个专辑。这使得删除设备上的文件对我来说无趣

于 2020-03-16T13:44:53.353 回答
0

我也遇到了同样的问题,但是华为型号的图像和视频文件失败了。

我发现有一些关于它的报告错误,尽管谷歌已经丢弃了其中的 2 个,因为它们无法重现它。我建议你给他们加星标并添加更多细节。

https://issuetracker.google.com/issues/157714528

https://issuetracker.google.com/issues/142270549

https://issuetracker.google.com/issues/145348304

更新:

我创建了一个新的问题单,因为上面的一些已被谷歌丢弃,因为不可复制:

https://issuetracker.google.com/issues/184355104

于 2021-04-03T08:45:06.500 回答
0

我通过选择退出范围存储( android:requestLegacyExternalStorage="true") 并为 Android 10 请求 WRITE_EXTERNAL_STORAGE ,在我的 Android 10 应用程序中解决了这个问题:

<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="29"
    tools:ignore="ScopedStorage" />

然后ContentResolver.delete不会触发 RecoverableSecurityException 并且还会从磁盘中删除文件鉴于您请求并被授予 Manifest.permission.WRITE_EXTERNAL_STORAGE 权限。

注意:如果您不关心删除不是由您的应用程序创建或由您的应用程序以前安装创建的文件,那么您不需要请求该权限。

于 2020-12-20T04:43:11.870 回答