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

获取Android相册文件夹及读取非DCIM路径照片方法咨询

Android实现按相册展示照片:获取系统相册文件夹与读取全路径照片

一、获取系统相册文件夹

Android系统的相册本质是按文件夹分组的图片集合,推荐使用MediaStore ContentProvider来获取,这是官方适配所有Android版本(尤其是Android 10+ Scoped Storage)的标准方式。

1. 申请必要权限

  • Android 13及以上:在Manifest中声明<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />,无需动态申请(系统自动授予)。
  • Android 10-12:声明<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />,并在运行时动态申请该权限。
  • Android 9及以下:仅需声明READ_EXTERNAL_STORAGE权限。

2. 通过MediaStore查询相册分组

通过查询MediaStore.Images.Media.EXTERNAL_CONTENT_URI,按相册名称(BUCKET_DISPLAY_NAME)分组,获取每个相册的名称、封面图、图片数量等核心信息:

import android.content.ContentResolver
import android.net.Uri
import android.provider.MediaStore
import androidx.core.content.ContentUris

// 定义相册数据结构
data class Album(
    val id: Long,
    val name: String,
    val coverImageUri: Uri,
    val imageCount: Int,
    val relativePath: String
)

fun queryAlbums(contentResolver: ContentResolver): List<Album> {
    val albumMap = mutableMapOf<String, Album>()

    // 指定查询字段
    val projection = arrayOf(
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
        MediaStore.Images.Media.BUCKET_ID,
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.RELATIVE_PATH
    )

    // 过滤JPG/PNG类型图片
    val selection = "${MediaStore.Images.Media.MIME_TYPE} IN (?, ?)"
    val selectionArgs = arrayOf("image/jpeg", "image/png")

    // 按修改时间倒序,确保封面取最新图片
    val sortOrder = "${MediaStore.Images.Media.DATE_MODIFIED} DESC"

    contentResolver.query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        projection,
        selection,
        selectionArgs,
        sortOrder
    )?.use { cursor ->
        val bucketNameCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
        val bucketIdCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID)
        val imageIdCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
        val relativePathCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.RELATIVE_PATH)

        while (cursor.moveToNext()) {
            val bucketName = cursor.getString(bucketNameCol)
            val bucketId = cursor.getLong(bucketIdCol)
            val imageId = cursor.getLong(imageIdCol)
            val relativePath = cursor.getString(relativePathCol)
            val coverUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId)

            // 分组统计相册信息
            albumMap.getOrPut(bucketName) {
                Album(
                    id = bucketId,
                    name = bucketName,
                    coverImageUri = coverUri,
                    imageCount = 0,
                    relativePath = relativePath
                )
            }.apply { imageCount++ }
        }
    }

    return albumMap.values.toList()
}

这段代码会返回所有系统识别的相册,包括DCIM、Pictures、Download等目录下的文件夹。

二、读取DCIM路径以外的照片

MediaStore默认会索引所有公共存储目录(如Pictures、Download、Movies、Documents等)下的图片文件,无需额外操作即可读取这些路径的照片,核心注意点如下:

1. 禁止直接遍历文件路径

Android 10+引入Scoped Storage后,禁止直接访问公共存储的文件路径(除非申请MANAGE_EXTERNAL_STORAGE权限,该权限需Google Play特殊审核,不推荐使用)。所有图片读取必须通过MediaStore进行。

2. 确保权限覆盖全场景

  • 对于Android 10-12,若需兼容旧代码,可在Manifest的<application>标签中添加android:requestLegacyExternalStorage="true",但这只是过渡方案,最终应完全迁移到MediaStore方式。
  • 查询时不要添加DCIM路径过滤条件,确保查询覆盖所有图片资源。

3. 加载非DCIM路径的图片

通过上述查询得到的Album对象中,coverImageUri可直接用于图片加载(如使用Glide):

Glide.with(context)
    .load(album.coverImageUri)
    .into(imageView)

若要获取某个相册下的所有图片,只需基于该相册的BUCKET_ID再次查询MediaStore:

fun queryAlbumImages(contentResolver: ContentResolver, bucketId: Long): List<Uri> {
    val images = mutableListOf<Uri>()
    val projection = arrayOf(MediaStore.Images.Media._ID)
    val selection = "${MediaStore.Images.Media.BUCKET_ID} = ?"
    val selectionArgs = arrayOf(bucketId.toString())
    val sortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"

    contentResolver.query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        projection,
        selection,
        selectionArgs,
        sortOrder
    )?.use { cursor ->
        val imageIdCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
        while (cursor.moveToNext()) {
            val imageId = cursor.getLong(imageIdCol)
            images.add(ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId))
        }
    }
    return images
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:56:01