You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 14中图库视频删除功能失效问题求助

问题分析

你遇到的删除失败问题,核心原因是Android 13+的媒体权限模型变化:添加READ_MEDIA_VISUAL_USER_SELECTED后,该权限仅允许访问用户手动选择的媒体,不具备删除权限;同时WRITE_EXTERNAL_STORAGE在Android 13+对媒体文件已失效,无法提供删除所需的写入权限。之前代码能正常运行是因为旧权限模型下WRITE_EXTERNAL_STORAGE拥有全存储访问权限。

解决方案

1. 调整Manifest权限

针对不同系统版本配置对应权限,确保删除操作的权限合法性:

<!-- Android 12及以下保留WRITE_EXTERNAL_STORAGE -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<!-- Android 13+添加专门的视频写入/删除权限 -->
<uses-permission android:name="android.permission.WRITE_MEDIA_VIDEO" android:minSdkVersion="33"/>

2. 动态申请删除权限

在删除操作前,需先检查并申请对应权限:

private const val REQUEST_DELETE_PERMISSION = 1001

private fun checkDeletePermission(): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED
    } else {
        ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
    }
}

private fun requestDeletePermissions() {
    val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(Manifest.permission.WRITE_MEDIA_VIDEO)
    } else {
        arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }
    ActivityCompat.requestPermissions(this, permissions, REQUEST_DELETE_PERMISSION)
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_DELETE_PERMISSION) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            binding.deleteVideoButton.performClick()
        } else {
            Toast.makeText(this, getString(R.string.permission_required_for_deletion), Toast.LENGTH_SHORT).show()
        }
    }
}

3. 修改删除逻辑(通过ContentResolver操作MediaStore)

Android 13+推荐通过MediaStore操作媒体文件,避免直接File操作的权限问题:
首先添加工具函数获取视频在MediaStore中的Uri:

fun getVideoUriByFileName(context: Context, fileName: String): Uri? {
    val projection = arrayOf(MediaStore.Video.Media._ID)
    val selection = "${MediaStore.Video.Media.DISPLAY_NAME} = ?"
    val selectionArgs = arrayOf(fileName)
    
    context.contentResolver.query(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        projection,
        selection,
        selectionArgs,
        null
    )?.use { cursor ->
        if (cursor.moveToFirst()) {
            val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID))
            return ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
        }
    }
    return null
}

然后替换原删除逻辑中的协程代码:

CoroutineScope(Dispatchers.IO).launch {
    val videoFileName = file.name
    val videoUri = getVideoUriByFileName(applicationContext, videoFileName)
    
    val deletedCount = if (videoUri != null) {
        try {
            applicationContext.contentResolver.delete(videoUri, null, null)
        } catch (e: SecurityException) {
            0
        }
    } else {
        // 兼容找不到MediaStore条目的情况,尝试直接删除文件
        if (file.delete()) 1 else 0
    }

    withContext(Dispatchers.Main) {
        binding.progressBar.visibility = View.GONE
        if (deletedCount > 0) {
            val tempoVideos = Utilities.listVideos(applicationContext)
            val tempoThumbnails = Utilities.convertFilesToBitmaps(tempoVideos.take(5))
            val tempoUris = tempoVideos.map { Uri.fromFile(it) }
            
            if (tempoUris.isNotEmpty()) {
                currentVideoUri = tempoUris[0]
                preparePlayer(currentVideoUri)
            }
            adapter.updateThumbnails(tempoThumbnails, tempoUris)
            loadRemainingBitmaps(tempoVideos.drop(5))
        } else {
            Toast.makeText(this@PreviewActivity,
                getString(R.string.failed_to_delete_video),
                Toast.LENGTH_SHORT).show()
        }
    }
}

4. 更新删除按钮点击事件

在原点击逻辑开头添加权限检查:

binding.deleteVideoButton.setOnClickListener {
    if (!checkDeletePermission()) {
        requestDeletePermissions()
        return@setOnClickListener
    }
    
    // 原有的文件检查、弹窗逻辑...
}

内容的提问来源于stack exchange,提问作者NeroVero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 08:19:52