Android读取Pictures/TestApp目录图片无结果,求代码运行故障原因
核心问题原因
- 低版本系统字段不兼容
MediaStore.MediaColumns.RELATIVE_PATH是Android 10(API 29)才新增的字段,API 28及以下的系统不存在这个字段,直接用该字段作为查询条件会导致查询失败,返回空结果。 - RELATIVE_PATH匹配规则错误
MediaStore存储的RELATIVE_PATH默认末尾带有斜杠,你当前写的匹配规则是Pictures/TestApp%,实际系统存储的路径是Pictures/TestApp/,匹配规则不匹配导致查不到结果。 - 存储权限未正确申请
不同Android版本要求的存储权限不同,如果未申请对应权限或者权限被拒绝,MediaStore查询会直接返回空游标。 - 低版本保存逻辑缺失目录创建步骤
API 28及以下的保存逻辑中,你没有判断目标目录是否存在,直接创建文件输出流会导致保存失败,自然没有图片可查。 - MediaStore未及时刷新
低版本系统直接写入本地文件后,MediaStore不会自动扫描更新,刚保存的图片不会立刻出现在查询结果中。
修复方案
第一步:确认权限配置
根据你适配的系统版本申请对应权限,所有权限需要动态申请通过后再执行查询操作:
- API 33及以上:申请
READ_MEDIA_IMAGES权限 - API 29~32:申请
READ_EXTERNAL_STORAGE权限 - API 28及以下:申请
READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限
第二步:修复保存逻辑
给低版本保存逻辑添加目录创建判断,高版本RELATIVE_PATH补全末尾斜杠:
private fun saveMediaToStorage(bitmap: Bitmap) { val filename = "${System.currentTimeMillis()}.jpg" var fos: OutputStream? = null if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { this.contentResolver?.also { resolver -> val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg") // 给RELATIVE_PATH末尾加上斜杠,符合系统存储规范 put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES+ File.separator + "TestApp" + File.separator) put(MediaStore.Images.Media.WIDTH, bitmap.width) put(MediaStore.Images.Media.HEIGHT, bitmap.height) } val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) fos = imageUri?.let { resolver.openOutputStream(it) } } } else { val imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES+ File.separator + "TestApp") // 新增目录创建判断 if (!imagesDir.exists()) { imagesDir.mkdirs() } val image = File(imagesDir, filename) fos = FileOutputStream(image) // 低版本保存后通知MediaStore刷新 sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(image))) } fos?.use { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it) Toast.makeText(this, "saved the image", Toast.LENGTH_SHORT).show() } }
第三步:修复查询逻辑,适配多版本
private suspend fun loadPhotosFromExternalStorage(): List<UserWork> { return withContext(Dispatchers.IO) { val collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME ) val photos = mutableListOf<UserWork>() // 分版本构造查询条件 val selection: String val selectionArgs: Array<String> val targetDirPath = Environment.DIRECTORY_PICTURES + File.separator + "TestApp" + File.separator if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { selection = "${MediaStore.MediaColumns.RELATIVE_PATH} LIKE ?" selectionArgs = arrayOf("${targetDirPath}%") } else { // 低版本用DATA字段匹配绝对路径 val targetAbsoluteDir = Environment.getExternalStoragePublicDirectory(targetDirPath).absolutePath selection = "${MediaStore.Images.Media.DATA} LIKE ?" selectionArgs = arrayOf("${targetAbsoluteDir}%") } requireActivity().contentResolver.query( collection, projection, selection, selectionArgs, "${MediaStore.Images.Media.DATE_ADDED} DESC" // 按添加时间排序比文件名排序更准确 )?.use { cursor -> val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val displayNameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME) while (cursor.moveToNext()) { val id = cursor.getLong(idColumn) val displayName = cursor.getString(displayNameColumn) val contentUri = ContentUris.withAppendedId( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id ) photos.add(UserWork(id, displayName, contentUri)) } photos.toList() } ?: listOf() } }
内容的提问来源于stack exchange,提问作者sejigner
相关产品推荐
相关产品推荐

