获取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
相关产品推荐
相关产品推荐

