Android Java:Android11及高低版本图片存读与RecyclerView适配问题
Android 11+ 图片存读适配方案(适配Scoped Storage)
一、保存图片到图库指定文件夹
Android 11及以上强制启用Scoped Storage,无法直接通过文件路径写入公共存储目录,必须使用MediaStore API完成写入操作,以下是具体实现:
核心逻辑:
- 构建
ContentValues,指定目标文件夹(如Pictures/我的绘画作品)、文件名、MIME类型等信息 - 通过
ContentResolver将图片元数据插入MediaStore,获取可写入的Uri - 通过输出流将绘制的
Bitmap写入该Uri - 通知系统图库刷新,确保图片立即显示
Java代码示例:
public void saveBitmapToGallery(Context context, Bitmap bitmap, String fileName) { // 指定图库中的目标文件夹:Pictures/我的绘画作品 String relativePath = Environment.DIRECTORY_PICTURES + "/我的绘画作品"; ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/png"); values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath); // 获取ContentResolver并插入MediaStore ContentResolver resolver = context.getContentResolver(); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = resolver.openOutputStream(uri)) { // 将Bitmap写入输出流,这里以PNG为例,可根据需求改为JPEG bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); // 通知图库刷新 resolver.notifyChange(uri, null); } catch (IOException e) { e.printStackTrace(); // 插入失败时删除无效条目 resolver.delete(uri, null, null); } } }
二、读取指定文件夹图片到RecyclerView
同样通过MediaStore查询目标文件夹下的图片,避免直接访问文件路径,以下是实现方式:
核心逻辑:
- 构建查询条件,筛选出目标文件夹下的图片
- 从查询结果中提取图片的
Uri(Android 10+不建议直接使用DATA字段) - 将
Uri列表传给RecyclerView Adapter,通过图片加载库或ContentResolver加载图片
Java代码示例:
1. 查询目标文件夹图片
public List<Uri> queryGalleryFolderImages(Context context) { List<Uri> imageUris = new ArrayList<>(); String targetFolder = Environment.DIRECTORY_PICTURES + "/我的绘画作品"; // 查询需要的字段 String[] projection = { MediaStore.Images.Media._ID, MediaStore.Images.Media.RELATIVE_PATH }; // 筛选条件:匹配目标文件夹 String selection = MediaStore.Images.Media.RELATIVE_PATH + " = ?"; String[] selectionArgs = {targetFolder + "/"}; // 注意末尾的斜杠 // 按添加时间倒序排列 String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC"; try (Cursor cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder )) { if (cursor != null && cursor.moveToFirst()) { int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID); do { long id = cursor.getLong(idColumn); // 构建图片的Content Uri Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id); imageUris.add(uri); } while (cursor.moveToNext()); } } catch (Exception e) { e.printStackTrace(); } return imageUris; }
2. RecyclerView Adapter中加载图片
以Glide为例(需添加Glide依赖):
@Override public void onBindViewHolder(ImageViewHolder holder, int position) { Uri imageUri = imageUris.get(position); Glide.with(holder.itemView.getContext()) .load(imageUri) .into(holder.imageView); }
三、权限适配
- Android 13及以上:需申请
READ_MEDIA_IMAGES权限(读取图片),保存图片无需额外权限 - Android 11-12:需申请
READ_EXTERNAL_STORAGE权限(读取图片),保存图片无需WRITE_EXTERNAL_STORAGE - Android 10及以下:需申请
WRITE_EXTERNAL_STORAGE权限(保存)和READ_EXTERNAL_STORAGE权限(读取)
在Manifest中声明权限:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
内容的提问来源于stack exchange,提问作者Ravi_Makani
相关产品推荐
相关产品推荐

