Android Studio中自定义相机拍摄图片如何设置到GridView并传递路径
代码存在的核心问题
- 异步执行逻辑顺序错误:
camera.takePicture()是异步操作,点击拍照按钮后立刻读取文件路径,此时图片还未写入存储,拿到的是空或者旧文件。且拍照按钮里创建的Intent未调用startActivity(),参数根本没有传递到相册页。 - 传参类型不匹配:MainActivity中存入Intent的是字符串类型的图片路径,CustomGallary中却按Bitmap类型读取,必然返回null。
- 存储权限缺失:仅申请了相机权限,未申请存储读写权限,安卓10以下无法写入外部存储,安卓13以上无法读取公共目录图片。
- 图片命名重复:保存的图片固定命名为
temp.jpg,每次拍照都会覆盖上一张,最终相册只能看到最新一张图片。 - GridView适配器使用错误:系统默认
ArrayAdapter仅适配TextView布局,无法直接加载Bitmap到ImageView,需要自定义适配器。 - 相册页逻辑错误:仅尝试读取传入的单张图片,没有扫描存储自定义图片的GUI文件夹下的所有图片,不符合自定义相册的功能需求。
修复方案
1. 修复MainActivity逻辑
补全权限申请
在AndroidManifest.xml中添加权限:
<!-- 相机权限 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 安卓9及以下存储写入权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <!-- 安卓13及以上图片读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
在MainActivity的权限申请逻辑中,同步申请存储相关权限。
修改图片命名逻辑,避免覆盖
修改getOutputMediaFile()方法,用时间戳作为文件名:
private File getOutputMediaFile() { String state= Environment.getExternalStorageState(); if(!state.equals(Environment.MEDIA_MOUNTED)) { return null; } else { File folder_gui= new File(Environment.getExternalStorageDirectory()+ File.separator + "GUI"); if(!folder_gui.exists()) { folder_gui.mkdirs(); } // 用时间戳命名避免覆盖 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); File outputFile= new File(folder_gui,"IMG_"+timeStamp+".jpg"); return outputFile; } }
调整跳转时机,确保图片写入完成后再操作
修改PictureCallback,图片写入完成后如果需要直接跳转相册可以在这里触发:
Camera.PictureCallback mpictureCallback=new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File picture_file = getOutputMediaFile(); if(picture_file== null) { return; } else { try { FileOutputStream fos=new FileOutputStream(picture_file); fos.write(data); fos.close(); // 通知系统媒体库更新,方便其他应用识别到新图片 sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(picture_file))); camera.startPreview(); // 如果需要拍完照直接跳相册,在这里启动Intent Intent i=new Intent(MainActivity.this,CustomGallary.class); startActivity(i); } catch (IOException e) { e.printStackTrace(); } } } };
2. 修复CustomGallary逻辑
扫描GUI文件夹获取所有图片路径
不要从Intent传单张路径,直接扫描目标文件夹下所有图片:
private ArrayList<String> getAllImagePaths() { ArrayList<String> imagePaths = new ArrayList<>(); File folder = new File(Environment.getExternalStorageDirectory() + File.separator + "GUI"); if (folder.exists() && folder.isDirectory()) { File[] files = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".jpg") || name.toLowerCase().endsWith(".png")); if (files != null) { for (File file : files) { imagePaths.add(file.getAbsolutePath()); } } } // 按时间倒序排列,最新的图片在最前面 Collections.reverse(imagePaths); return imagePaths; }
自定义GridView适配器
public class ImageGridAdapter extends BaseAdapter { private Context mContext; private ArrayList<String> mImagePaths; public ImageGridAdapter(Context context, ArrayList<String> paths) { mContext = context; mImagePaths = paths; } @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 = new ImageView(mContext); imageView.setLayoutParams(new GridView.LayoutParams(300, 300)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); } else { imageView = (ImageView) convertView; } // 采样压缩加载图片,避免OOM Bitmap bitmap = decodeSampledBitmapFromPath(mImagePaths.get(position), 300, 300); imageView.setImageBitmap(bitmap); // 点击图片跳转下一页的逻辑,把路径传过去 imageView.setOnClickListener(v -> { Intent intent = new Intent(mContext, NextActivity.class); intent.putExtra("image_path", mImagePaths.get(position)); mContext.startActivity(intent); }); return imageView; } // 图片采样压缩方法 private Bitmap decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(path, options); } private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; } }
修改CustomGallary的onCreate逻辑
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.image_view); GridView mygrid=findViewById(R.id.gv); // 获取所有图片路径 ArrayList<String> imagePaths = getAllImagePaths(); // 设置自定义适配器 ImageGridAdapter adapter = new ImageGridAdapter(this, imagePaths); mygrid.setAdapter(adapter); }
3. 跨页面传图片路径的方法
直接在Intent中存入字符串类型的路径即可,下一页接收后再加载图片:
// 发送页 Intent intent = new Intent(CurrentActivity.this, TargetActivity.class); intent.putExtra("image_path", 图片的绝对路径); startActivity(intent); // 接收页 String imagePath = getIntent().getStringExtra("image_path"); // 之后加载图片到ImageView即可
内容的提问来源于stack exchange,提问作者Pratiksha
相关产品推荐
相关产品推荐

