Android Q - 删除媒体(音频)文件

Android Q - Delete Media (Audio) File

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

到目前为止,这是我的解决方案:

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, 0 ,0, 0,
                            null);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            });

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

所以在多次 Google 搜索之后,我得出的结论是,最好的方法(据我所知)是简单地关闭 Android Q (10) 的分区存储。

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

解决方案 1 - 关闭分区存储

对于此解决方案,您仍然可以针对 Android11。您所要做的就是转到模块级别的 build.gradle 文件并设置 compileSdkVersiontargetSdkVersion30.

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

<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"
    ...

完成后,您可以使用内容解析器删除媒体文件(并更新媒体商店),您不必担心像 Android 中所说的那样捕获安全异常文档。您对 Android 11 秒删除操作的实施不应受到影响。

解决方案 2 - 打开分区存储

首先,在您的清单中确保 WRITE_EXTERNAL_STORAGE 权限 maxSdkVersion 设置为 28。还要确保 requestLegacyExternalStorage 设置为 false(不要认为这是必需的)。然后干脆复制我原来post中的代码。如果您从 activity/fragment 执行删除操作,则不需要实时数据。但是你应该注意 startIntentSenderForResult() 需要一个 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 上删除,您只需调用 createDeleteRequest() 即可 return 和 PendingIntent。从此 PendingIntent 您可以使用 getIntentSender 获得 IntentSender。将此意图发送者传递给 activity/fragment,然后在您的 activity/fragment 中调用 startIntentSenderForResult()。这会向用户弹出一个对话框,询问他们应用程序是否可以删除文件。如果用户授予权限,系统会继续删除文件并更新媒体存储。

旁注 - 分区存储,Android 10 和 Future

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