问题描述
我一直在尝试让我的应用程序能够删除音频文件。然而,在尝试了许多可能的解决方案之后,我无法真正找到一种有效的方法。
这是我目前的解决方案:
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
文件并将 compileSdkVersion
和 targetSdkVersion
设置为 {{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 中使用。但我必须对此进行更多研究......