如何让MediaStore.MediaColumns.DATA兼容Android 10并正常加载图库图片
解决Android 10下MediaStore.DATA兼容问题的方案
这个问题我太熟悉了——Android 10(API 29)引入的**分区存储(Scoped Storage)**直接废掉了MediaStore.MediaColumns.DATA的可用性,真机上这个字段会返回空值或null,自然加载不出图片。咱们直接从根源修改代码:
1. 重构图片列表获取逻辑(ImagesGallery类)
放弃DATA字段,改用媒体文件的_ID构建官方推荐的Content URI来访问图片,这是分区存储下的标准做法:
public class ImagesGallery { // 移除@SuppressLint("Recycle"),咱们要手动关闭Cursor避免内存泄漏 @RequiresApi(api = Build.VERSION_CODES.Q) public static ArrayList<Uri> listOfImages(Context context){ Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; // 只查询媒体文件的ID字段即可 String[] projection = new String[]{MediaStore.Images.Media._ID}; String orderBy = MediaStore.Images.Media.DATE_TAKEN; Cursor cursor = context.getContentResolver().query( mediaUri, projection, null, null, orderBy + " DESC" ); ArrayList<Uri> imageUris = new ArrayList<>(); if (cursor != null){ int idColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID); while (cursor.moveToNext()){ long imageId = cursor.getLong(idColumnIndex); // 用ID构建Content URI,这是访问媒体文件的标准方式 Uri imageUri = ContentUris.withAppendedId(mediaUri, imageId); imageUris.add(imageUri); } // 必须关闭Cursor,避免内存泄漏 cursor.close(); } return imageUris; } }
2. 调整Activity中的加载逻辑
因为现在返回的是Uri列表,所以要修改Adapter的回调参数和Glide加载方式:
// 先把mList的类型改成ArrayList<Uri> private ArrayList<Uri> mList; private void loadImages() { recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new GridLayoutManager(this, 4)); mList = ImagesGallery.listOfImages(this); galleryAdapter = new GalleryAdapter(PhotoActivity.this, mList, new GalleryAdapter.PhotoListener() { @Override public void onPhotoClick(Uri imageUri) { // 参数从String改成Uri // Glide直接支持加载Content URI,无需转成文件路径 Glide.with(PhotoActivity.this).load(imageUri).into(image); imageData = imageUri; // 直接使用这个Uri即可 } }); recyclerView.setAdapter(galleryAdapter); gallery_number.setText("Photos (" + mList.size() + ")"); }
3. 适配GalleryAdapter
记得把Adapter的数据源类型从ArrayList<String>改成ArrayList<Uri>,对应的ViewHolder中加载图片时,直接用Glide加载Uri就行,比如:
// 示例Adapter中的onBindViewHolder方法 @Override public void onBindViewHolder(GalleryViewHolder holder, int position) { Uri imageUri = mList.get(position); Glide.with(mContext) .load(imageUri) .centerCrop() .into(holder.imageView); }
关键注意点
- 权限问题:确保已经申请了
READ_EXTERNAL_STORAGE权限,Android 10及以上即使有这个权限,也不能直接访问文件路径,但通过Content URI访问媒体文件是允许的。 - 兼容性:如果需要兼容Android 9及以下,可在
listOfImages中做版本判断——旧版本可以继续用DATA字段,或者统一用Uri(Glide在旧版本也支持加载Content URI)。 - Cursor关闭:之前的代码没有关闭Cursor,会导致内存泄漏,一定要补上
cursor.close()。
内容的提问来源于stack exchange,提问作者M C
相关产品推荐
相关产品推荐

