Android Q - 删除媒体音频文件

问题描述

我一直在尝试让我的应用程序能够删除音频文件。然而,在尝试了许多可能的解决方案之后,我无法真正找到一种有效的方法

这是我目前的解决方案:

public static void deleteFiles(List<Track> tracks,Context context,final mutablelivedata<IntentSender> deletionIntentSenderLD){

        final Uri AUdio_URI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

        for(Track t : tracks){
            try {

                context.getContentResolver().delete(ContentUris
                        .withAppendedId(AUdio_URI,t.getUriId()),null,null);

            }catch (SecurityException securityException) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

                    if (securityException instanceof RecoverableSecurityException) {

                        deletionIntentSenderLD
                                .postValue(((RecoverableSecurityException) securityException)
                                        .getUserAction().getActionIntent().getIntentSender());

                    } else
                        throw securityException;

                } else
                    throw securityException;

            }

        }

    }

当 try 块失败时,捕获 SecurityException,然后将 IntentSender 传递给在片段中观察到的实时数据:

audioviewmodel.getDeletionIntentSenderLD().observe(getViewLifecycleOwner(),intentSender -> {
                try {
                    startIntentSenderForResult(intentSender,DELETE_PERMISSION_REQUEST,null);
                } catch (IntentSender.SendIntentException e) {
                    e.printstacktrace();
                }
            });

我已经尝试实现 onRequestPermissionResult() 方法,但是没有任何作用。我还尝试使用 File file = new File() 删除文件,但是,由于对 Android 10 所做的更改,我没想到它会起作用。

解决方法

经过多次 Google 搜索后,我得出的结论是(据我所知)最好的方法是简单地关闭 Android Q (10) 的范围存储。

在这里,我将提供两种解决方案。第一个是我关闭它的那个,第二个是仍然启用范围存储的那个。但是,您应该注意的是,第二个解决方案有点问题,有时它实际上确实删除了实际的媒体文件并更新了媒体商店,但大多数时候它只是从媒体商店中删除。显然,这不是一个很好的解决方案,因为在重新启动时,您的应用程序会重新加载这些文件,因为媒体商店会扫描它们。

解决方案 1 - 关闭范围存储

对于此解决方案,您仍然可以针对 Android 11。您只需转到模块级别的 build.gradle 文件并将 compileSdkVersiontargetSdkVersion 设置为 {{1 }}。

之后,您进入 30 并像这样设置使用权限和应用程序标签:

AndroidManifest.xml

完成此操作后,您可以使用 Content Resolver 删除媒体文件(并更新媒体存储),并且您不必担心会像 Android 文档中所说的那样捕获安全异常。您对 Android 11s 删除操作的实施不应受到影响。

解决方案 2 - 打开范围存储

首先,在您的清单中确保 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" tools:ignore="ScopedStorage"/> <application android:requestLegacyExternalStorage="true" ... 权限 WRITE_EXTERNAL_STORAGE 设置为 maxSdkVersion。还要确保将 28 设置为 requestLegacyExternalStorage(不认为这是必需的)。然后只需复制我原始帖子中的代码即可。如果您从活动/片段中执行删除操作,则不需要实时数据。但您应该注意 false 需要一个 Activity。

但正如我之前提到的,我确实遇到了一些错误。但是,此解决方案最令人沮丧的是它不会删除实际文件,而是从媒体商店中删除条目。也许这与@blackapps 提到的事实有关,那就是你不能批量删除,我可能在实现上有点错误。尽管如此,如果在 Android 10 中无法批量删除,这对用户体验来说是很糟糕的。

我遵循的教程是:

https://developer.android.com/training/data-storage/shared/media#remove-item

https://www.raywenderlich.com/9577211-scoped-storage-in-android-10-getting-started#toc-anchor-007

https://www.solutionanalysts.com/blog/scoped-storage-in-android-10/

旁注 - 在 Android 11 上删除

要在 Android 11 上删除,您只需调用 startIntentSenderForResult(),它应该返回 createDeleteRequest()。从这个 PendingIntent 中,您可以使用 PendingIntent 获得 IntentSender。将此意图发送者传递给活动/片段,然后在您的活动/片段中调用 getIntentSender。这会向用户弹出一个对话框,询问他们应用程序是否可以删除文件。如果用户授予权限,系统会继续删除文件并更新媒体存储。

旁注 - Scoped Storage、Android 10 和未来

从我所看到的一切来看,似乎表明范围存储仅在 Android 11 中强制执行,但我不完全确定旧选项是否仍可无限期地在 Android 10 中使用。但我必须对此进行更多研究......