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

如何在RecyclerView中同时列出视频文件及其所在文件夹?

获取视频文件所在文件夹并在RecyclerView中展示

我来帮你搞定这个需求~要在RecyclerView里同时展示视频文件和它们所在的文件夹,关键是先从MediaStore里拿到文件夹路径,然后做去重和数据区分,具体步骤如下:

1. 修改MediaStore查询的投影字段

首先,你需要扩展查询的projection数组,加入能获取文件路径的字段。Android 10(API 29)及以上推荐使用RELATIVE_PATH,它返回的是相对于外部存储的相对路径(比如"Movies/");更早的版本可以用DATA获取完整文件路径。为了兼容,你可以同时加入这两个字段:

val projection = arrayOf(
    MediaStore.Video.Media.DISPLAY_NAME,
    MediaStore.Video.Media.RELATIVE_PATH, // Android 10+ 适用
    MediaStore.Video.Media.DATA // 旧版本兼容
)

2. 查询并提取文件夹信息,做去重处理

接下来,遍历cursor的时候,提取每个视频的文件夹路径,用一个集合来记录已经处理过的文件夹,避免重复添加。同时,建议创建一个密封类来区分“文件夹”和“视频文件”两种类型,方便后续RecyclerView适配:

首先定义数据类:

sealed class MediaItem {
    data class VideoFile(val name: String) : MediaItem()
    data class Folder(val name: String) : MediaItem()
}

然后处理cursor(用use函数可以自动关闭cursor,省去手动close的步骤):

val mediaItems = mutableListOf<MediaItem>()
val processedFolders = mutableSetOf<String>() // 用于去重文件夹,确保每个文件夹只显示一次

val cursor = CursorLoader(
    applicationContext,
    MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
    projection,
    null,
    null,
    null
).loadInBackground()

cursor?.use {
    while (it.moveToNext()) {
        val videoName = it.getString(it.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME))
        // 添加当前视频到列表
        mediaItems.add(MediaItem.VideoFile(videoName))

        // 根据系统版本获取文件夹路径
        val folderName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val relativePath = it.getString(it.getColumnIndex(MediaStore.Video.Media.RELATIVE_PATH))
            relativePath?.trimEnd('/') // 去掉末尾的斜杠,显示更友好
        } else {
            val fullPath = it.getString(it.getColumnIndex(MediaStore.Video.Media.DATA))
            // 从完整路径中提取文件夹名称
            File(fullPath).parentFile?.name
        }

        folderName?.let { name ->
            // 如果这个文件夹还没被添加过,就加入列表
            if (processedFolders.add(name)) {
                mediaItems.add(MediaItem.Folder(name))
            }
        }
    }
}

3. 适配RecyclerView,区分显示文件夹和视频

接下来,在RecyclerView的Adapter里,根据MediaItem的类型加载不同的布局。你需要先创建两个布局文件:item_folder.xml(用于显示文件夹样式)和item_video.xml(用于显示视频文件样式)。

然后编写Adapter:

class MediaAdapter(private val items: List<MediaItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        private const val TYPE_FOLDER = 0
        private const val TYPE_VIDEO = 1
    }

    // 区分不同的item类型
    override fun getItemViewType(position: Int): Int {
        return when (items[position]) {
            is MediaItem.Folder -> TYPE_FOLDER
            is MediaItem.VideoFile -> TYPE_VIDEO
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            TYPE_FOLDER -> FolderViewHolder(inflater.inflate(R.layout.item_folder, parent, false))
            else -> VideoViewHolder(inflater.inflate(R.layout.item_video, parent, false))
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = items[position]) {
            is MediaItem.Folder -> (holder as FolderViewHolder).bind(item.name)
            is MediaItem.VideoFile -> (holder as VideoViewHolder).bind(item.name)
        }
    }

    override fun getItemCount() = items.size

    // 文件夹ViewHolder
    inner class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(folderName: String) {
            itemView.tv_folder_name.text = folderName
            // 可以在这里添加文件夹图标、点击事件等逻辑
        }
    }

    // 视频文件ViewHolder
    inner class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(videoName: String) {
            itemView.tv_video_name.text = videoName
            // 可以在这里添加视频缩略图、播放按钮等逻辑
        }
    }
}

额外优化提示

  • 排序调整:上面的代码会先添加视频再添加文件夹,你可以根据需求调整排序逻辑,比如先显示所有文件夹,再显示视频,或者按名称排序。
  • 权限适配:别忘了在AndroidManifest.xml中添加对应权限,Android 13+需要申请READ_MEDIA_VIDEO,旧版本需要READ_EXTERNAL_STORAGE。
  • 性能优化:如果视频文件较多,建议在后台线程处理cursor查询,避免阻塞主线程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:15:08