关于 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 设备可能对回收站有不同的实现,但您的方法是最通用的解决方案。

相关推荐
程序员Android4 分钟前
Android 刷新一帧流程trace拆解
android
墨狂之逸才34 分钟前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶1 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
汪海游龙2 小时前
开源项目 Trending AI 招募 Google Play 内测人员(12 名)
android·github
qq_283720053 小时前
MySQL技巧(四): EXPLAIN 关键参数详细解释
android·adb
没有了遇见3 小时前
Android 架构之网络框架多域名配置<三>
android
myloveasuka4 小时前
[Java]单列集合
android·java·开发语言
fundroid5 小时前
Room 3.0 完全解析:一次面向未来的现代化重构
android·数据库·database·kmp
漂洋过海来看你啊5 小时前
Jetpack Compose高效列表实战:状态管理与性能优化指南
android
张宏2365 小时前
android camera hal3-camera_module_t
android