高版本Android如何获取与getExternalStoragePublicDirectory一致的路径
问题原因说明
你之前用getExternalFilesDir()返回的是应用专属外部存储目录,路径为/Android/data/[应用包名]/files/Pictures/...,和你需要的公共相册Pictures目录下的Tackle Box文件夹不是同一路径,自然无法正常读写原来的图片。
从Android 10(API 29)开始,官方禁止直接访问公共存储的File路径,必须通过MediaStore API操作公共媒体文件,对应实现方案如下:
步骤1:配置清单权限
在AndroidManifest.xml中添加对应权限:
<!-- 读取外部存储,Android13以下生效 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 写入外部存储,Android9以下生效 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <!-- Android13及以上读取图片权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" /> <application ... <!-- Android10兼容配置,可选但建议添加 --> android:requestLegacyExternalStorage="true"> ... </application>
步骤2:写入图片到公共Tackle Box目录
// 构造图片元数据 val imageValues = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "示例图片.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") // 指定存储路径为公共Pictures/Tackle Box put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/Tackle Box/") put(MediaStore.Images.Media.IS_PENDING, 0) } // 插入到MediaStore获取图片Uri val imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues) // 写入图片数据 imageUri?.let { uri -> contentResolver.openOutputStream(uri)?.use { outputStream -> // 此处写入你的Bitmap/图片字节流,示例: // targetBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) } }
步骤3:读取Tackle Box目录下的所有图片
val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME ) // 筛选路径包含Pictures/Tackle Box的图片 val selection = "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?" val selectionArgs = arrayOf("%${Environment.DIRECTORY_PICTURES}/Tackle Box/%") val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder )?.use { cursor -> val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) while (cursor.moveToNext()) { val imageId = cursor.getLong(idColumn) // 拿到图片Uri,直接加载即可,不需要本地File路径 val loadUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId) // 示例用Glide加载: // Glide.with(context).load(loadUri).into(targetImageView) } }
低版本兼容(API 28及以下)
如果需要兼容Android 9及以下版本,可以保留原File逻辑单独适配:
val targetDir = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Tackle Box" ).apply { if (!exists()) mkdirs() } } else { // 高版本走MediaStore逻辑,不需要获取File路径 null }
内容的提问来源于stack exchange,提问作者JRowan
相关产品推荐
相关产品推荐

