如何创建自定义GridView画廊展示外部存储指定文件夹图片?
我明白你现在卡在自定义画廊展示外部指定文件夹图片的问题上了,之前试了各种方案都没成功,别着急,我给你一套完整可行的实现步骤,跟着做应该就能搞定:
第一步:先搞定存储权限
Android从6.0开始就要求动态申请危险权限,存储权限更是重点,不同版本的权限还有区别:
- 先在
AndroidManifest.xml里添加基础权限:<!-- Android 12及以下 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13+ --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> - 在Activity/Fragment里动态申请权限:
private static final int REQUEST_STORAGE_PERMISSION = 100; private void requestStoragePermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { ActivityResultContracts.RequestMultiplePermissions contract = new ActivityResultContracts.RequestMultiplePermissions(); registerForActivityResult(contract, result -> { Boolean isGranted = result.get(Manifest.permission.READ_MEDIA_IMAGES); if (isGranted != null && isGranted) { // 权限通过,开始加载图片 loadFolderImages(); } else { Toast.makeText(this, "需要存储权限才能查看图片", Toast.LENGTH_SHORT).show(); } }).launch(new String[]{Manifest.permission.READ_MEDIA_IMAGES}); } else { loadFolderImages(); } } else { // 处理Android 12及以下的权限申请 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityResultContracts.RequestPermission contract = new ActivityResultContracts.RequestPermission(); registerForActivityResult(contract, isGranted -> { if (isGranted) { loadFolderImages(); } else { Toast.makeText(this, "需要存储权限才能查看图片", Toast.LENGTH_SHORT).show(); } }).launch(Manifest.permission.READ_EXTERNAL_STORAGE); } else { loadFolderImages(); } } }
第二步:获取指定文件夹下的所有图片
写一个工具方法,传入你要展示的文件夹路径(比如Environment.getExternalStorageDirectory() + "/MyPictures/"),筛选出所有图片文件:
private List<String> getImagePathsFromFolder(String folderPath) { List<String> imagePaths = new ArrayList<>(); File folder = new File(folderPath); if (!folder.exists() || !folder.isDirectory()) { Toast.makeText(this, "文件夹不存在", Toast.LENGTH_SHORT).show(); return imagePaths; } // 筛选常见的图片格式 String[] imageExtensions = {"jpg", "jpeg", "png", "gif", "bmp"}; File[] files = folder.listFiles((dir, name) -> { String lowerName = name.toLowerCase(); for (String ext : imageExtensions) { if (lowerName.endsWith("." + ext)) { return true; } } return false; }); if (files != null) { for (File file : files) { imagePaths.add(file.getAbsolutePath()); } } return imagePaths; }
第三步:修改GridView的适配器
把你原来硬编码图片的适配器改成动态加载路径的版本,这里推荐用Glide来加载图片(比原生BitmapFactory更省心,还能处理内存问题),先在build.gradle里添加Glide依赖:
dependencies { implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' }
然后写适配器:
public class ImageGridAdapter extends BaseAdapter { private Context mContext; private List<String> mImagePaths; public ImageGridAdapter(Context context, List<String> imagePaths) { mContext = context; mImagePaths = imagePaths; } @Override public int getCount() { return mImagePaths.size(); } @Override public Object getItem(int position) { return mImagePaths.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { // 创建新的ImageView,适配GridView的列宽 imageView = new ImageView(mContext); imageView.setLayoutParams(new GridView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 300 // 可以根据需求调整高度 )); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(4, 4, 4, 4); } else { imageView = (ImageView) convertView; } // 用Glide加载图片 Glide.with(mContext) .load(new File(mImagePaths.get(position))) .into(imageView); return imageView; } }
第四步:绑定GridView并加载数据
在你的Activity的onCreate方法里,调用权限申请,权限通过后加载图片并设置适配器:
private GridView mGridView; private ImageGridAdapter mAdapter; private List<String> mImagePaths; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mGridView = findViewById(R.id.gridview); // 先申请权限 requestStoragePermission(); } private void loadFolderImages() { // 替换成你要展示的文件夹路径 String targetFolder = Environment.getExternalStorageDirectory() + "/MyCustomGallery/"; mImagePaths = getImagePathsFromFolder(targetFolder); mAdapter = new ImageGridAdapter(this, mImagePaths); mGridView.setAdapter(mAdapter); }
额外注意事项
- 如果你的目标是Android 10及以上,默认开启了分区存储,不能直接访问其他APP的文件夹,如果你要访问的是自己APP创建的文件夹,或者公共文件夹(比如DCIM、Pictures)是没问题的;如果要访问任意文件夹,需要使用**存储访问框架(SAF)**让用户手动选择文件夹。
- 记得处理文件夹为空的情况,比如给GridView加个空视图提示用户“当前文件夹没有图片”。
- Glide可以设置占位图和错误图,提升用户体验,比如:
Glide.with(mContext) .load(new File(mImagePaths.get(position))) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .into(imageView);
内容的提问来源于stack exchange,提问作者Disney
相关产品推荐
相关产品推荐

