You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:42:37