关于 Android 系统回收站的实现

您的观察非常正确。Android 系统的回收站实现通常是通过以下几种方式:

  • 文件名添加 .Trash 前缀,使文件在文件浏览器中被隐藏

  • 在 MediaStore 中将文件标记为 IS_TRASHED = 1

  • 有些设备会将文件移动到特定的 .Trash 目录

    // 创建文件条目时使用 .Trash 前缀 put(MediaStore.MediaColumns.DISPLAY_NAME, ".Trash-"+System.currentTimeMillis()/1000+"-"+fileName)

    // 然后在所有 URI 上设置 IS_TRASHED 标记 val values = ContentValues().apply { put(MediaStore.MediaColumns.IS_TRASHED, 1) } contentResolver.update(uri, values, null, null)

回收站实现的关键点

  • 文件名前缀:.Trash-[时间戳]-[原文件名] 是一种常见的格式

  • IS_TRASHED 标记:在 Android 11+ 上,这个标记告诉系统该文件已被移到回收站

  • 相对路径:将文件放在应用专属目录下,如 Pictures/应用名称/

  • 保留元数据:保存原始文件名和删除时间,以便将来可以恢复

    /**

    • 从回收站恢复文件 */ @RequiresApi(Build.VERSION_CODES.Q) suspend fun restoreFromTrash(context: Context, uri: Uri) = withContext(Dispatchers.IO) { try { val contentResolver = context.contentResolver

      kotlin 复制代码
       // 1. 获取当前文件名
       var fileName = ""
       contentResolver.query(
           uri,
           arrayOf(MediaStore.MediaColumns.DISPLAY_NAME),
           null,
           null,
           null
       )?.use { cursor ->
           if (cursor.moveToFirst()) {
               fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME))
           }
       }
       
       if (fileName.startsWith(".Trash-")) {
           // 2. 提取原始文件名
           val originalFileName = fileName.substringAfter("-", "").substringAfter("-", "")
           
           // 3. 更新文件属性
           val values = ContentValues().apply {
               put(MediaStore.MediaColumns.DISPLAY_NAME, originalFileName)
               put(MediaStore.MediaColumns.IS_TRASHED, 0)
           }
           
           // 4. 应用更新
           contentResolver.update(uri, values, null, null)
           LogMG.e("tagyy", "文件已从回收站恢复: $originalFileName")
           return@withContext true
       }

      } catch (e: Exception) { LogMG.e("tagyy", "从回收站恢复失败: ${e.message}") e.printStackTrace() } return@withContext false }

    /**

    • 获取回收站中的所有文件 */ @RequiresApi(Build.VERSION_CODES.Q) suspend fun getTrashFiles(context: Context) = withContext(Dispatchers.IO) { val trashFiles = mutableListOf() val contentResolver = context.contentResolver

      // 查询所有已标记为回收站的文件 val selection = " <math xmlns="http://www.w3.org/1998/Math/MathML"> M e d i a S t o r e . M e d i a C o l u m n s . I S T R A S H E D = ? O R {MediaStore.MediaColumns.IS_TRASHED} = ? OR </math>MediaStore.MediaColumns.ISTRASHED=?OR{MediaStore.MediaColumns.DISPLAY_NAME} LIKE ?" val selectionArgs = arrayOf("1", ".Trash-%")

      // 查询不同类型的媒体 val uriTypes = listOf( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MediaStore.Downloads.EXTERNAL_CONTENT_URI )

      for (uri in uriTypes) { contentResolver.query( uri, arrayOf(MediaStore.MediaColumns._ID), selection, selectionArgs, null )?.use { cursor -> while (cursor.moveToNext()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) trashFiles.add(ContentUris.withAppendedId(uri, id)) } } }

      return@withContext trashFiles }

总结

Android 系统回收站的实现主要依赖于:

  • 文件名前缀(.Trash-)

  • MediaStore 中的 IS_TRASHED 标记

  • 将文件放在特定目录

您的实现已经涵盖了这些关键点,应该能够正常工作。记住,不同厂商的 Android 设备可能对回收站有不同的实现,但您的方法是最通用的解决方案。

相关推荐
阿巴斯甜11 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker11 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952712 小时前
Andorid Google 登录接入文档
android
黄林晴13 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android