Android 10+设备如何无需MANAGE_EXTERNAL_STORAGE权限在视频播放器适配器删除视频文件
Android 10+无需MANAGE_EXTERNAL_STORAGE权限删除视频文件的方案(适配RecyclerView场景)
完全可以不用申请MANAGE_EXTERNAL_STORAGE权限实现播放后删除视频的功能,以下是针对不同存储场景的可行方案,以及适配RecyclerView+适配器的具体实现:
一、核心删除方案(分存储场景)
1. 应用私有目录下的视频
如果视频文件存放在应用私有目录(如getFilesDir()、getCacheDir(),或Android 11+的getExternalFilesDir(Environment.DIRECTORY_MOVIES)),直接通过File.delete()即可删除,无需任何存储权限——这是应用的专属空间,系统默认允许读写操作。
2. 公共媒体目录的视频(DCIM、Movies等)
在Android 10及以上的分区存储规则下,不能直接通过文件路径删除公共目录的视频,需借助MediaStore的ContentResolver操作,仅需申请对应权限:
- Android 10-12:申请
WRITE_EXTERNAL_STORAGE权限 - Android 13+:申请
MEDIA_VIDEO_WRITE权限(媒体权限细分后的专属权限)
示例删除代码:
fun deleteMediaStoreVideo(context: Context, videoUri: Uri): Boolean { return try { // 返回值为删除的行数,大于0则表示删除成功 context.contentResolver.delete(videoUri, null, null) > 0 } catch (e: Exception) { e.printStackTrace() false } }
3. 用户通过文件选择器选择的视频
如果视频是用户通过ACTION_OPEN_DOCUMENT等系统文件选择器选中的,可先获取持久化URI权限,之后用ContentResolver.delete()删除,无需存储权限(这是用户主动授权的单个文件访问权限)。
获取持久化权限的代码:
fun takePersistableUriPermission(context: Context, uri: Uri) { val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION context.contentResolver.takePersistableUriPermission(uri, takeFlags) }
二、适配RecyclerView+适配器场景
1. 数据源设计
为适配器的数据源添加存储类型标识,方便后续调用对应删除逻辑:
enum class VideoStorageType { PRIVATE, MEDIA_STORE, DOCUMENT_URI } data class VideoItem( val id: Long, val title: String, val playUrl: String, // 根据存储类型赋值对应字段 val privatePath: String? = null, val mediaStoreUri: Uri? = null, val documentUri: Uri? = null, val storageType: VideoStorageType )
2. 适配器内的删除逻辑处理
将删除操作放在子线程执行(避免阻塞UI),删除成功后更新数据源并通知RecyclerView刷新:
class VideoAdapter( private val videoList: MutableList<VideoItem>, private val context: Context ) : RecyclerView.Adapter<VideoAdapter.VideoViewHolder>() { inner class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val deleteBtn: Button = itemView.findViewById(R.id.btn_delete_after_play) val playerView: PlayerView = itemView.findViewById(R.id.player_view) init { // 假设播放器播放完成后触发删除 playerView.addOnCompletionListener { triggerDelete() } // 也支持手动点击删除按钮 deleteBtn.setOnClickListener { triggerDelete() } } private fun triggerDelete() { val position = adapterPosition if (position == RecyclerView.NO_POSITION) return val targetVideo = videoList[position] // 子线程执行删除 CoroutineScope(Dispatchers.IO).launch { val deleteSuccess = when (targetVideo.storageType) { VideoStorageType.PRIVATE -> { targetVideo.privatePath?.let { File(it).delete() } ?: false } VideoStorageType.MEDIA_STORE -> { targetVideo.mediaStoreUri?.let { deleteMediaStoreVideo(context, it) } ?: false } VideoStorageType.DOCUMENT_URI -> { targetVideo.documentUri?.let { context.contentResolver.delete(it, null, null) > 0 } ?: false } } // 主线程更新UI if (deleteSuccess) { withContext(Dispatchers.Main) { videoList.removeAt(position) notifyItemRemoved(position) // 可选:如果需要保持列表连续性,调用notifyItemRangeChanged notifyItemRangeChanged(position, videoList.size) } } } } } // 重写onCreateViewHolder、onBindViewHolder、getItemCount等方法... }
三、注意事项
- Android 10及以上禁止直接通过文件路径操作公共媒体目录的文件,必须使用
MediaStore接口 - Android 13+需替换原
WRITE_EXTERNAL_STORAGE权限为MEDIA_VIDEO_WRITE,避免权限申请被拒 - 对于用户选择的文件,务必在获取URI时调用
takePersistableUriPermission,否则应用重启后会丢失权限无法删除
内容的提问来源于stack exchange,提问作者Ayan Mishra
相关产品推荐
相关产品推荐

