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

Android开发:Glide加载外部存储菜谱图片失败及上传方法问询

解决Glide加载外部存储图片报错&菜谱图片上传问题

嘿,我来帮你搞定这两个问题——先是Glide加载图片报EFAULT (Bad address)的奇怪错误,再是实现让你姑姑上传图片到指定目录的需求。

一、修复Glide加载外部图片的EFAULT错误

明明文件存在且能读,Glide却加载失败,这个Bad address错误大概率是路径解析或者权限配置的问题,给你几个靠谱的解决方向:

1. 别硬编码路径!用系统API拿正确路径

硬写/sdcard/真的容易踩坑,不同设备的外部存储路径可能不一样(比如有些是/storage/emulated/0/),Glide解析这种硬编码路径时可能出问题。换成系统提供的API来获取公共图片目录:

// 获取系统公共Pictures目录
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
// 构建你的Recipes子目录
File recipesDir = new File(picturesDir, "Recipes");
// 确保目录存在,不存在就创建
if (!recipesDir.exists()) {
    recipesDir.mkdirs();
}
// 生成正确的图片文件对象
File imageFile = new File(recipesDir, "carrot_cake.jpg");

2. 检查权限配置是否到位

就算文件能被检测到,权限没配好也可能导致Glide加载失败:

  • 对于Android 10及以下,在AndroidManifest.xml里加这两个权限:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • 要是你用的是Android 10(API 29)及以上,且targetSdkVersion >=29,记得在<application>标签里加这句兼容旧逻辑:
    android:requestLegacyExternalStorage="true"
    
    (如果targetSdkVersion >=30,更推荐用MediaStore管理公共目录文件,但临时用这个属性能快速解决问题)

3. 给Glide传File对象而非字符串路径

直接传File对象给Glide,能减少路径字符串解析时的潜在问题,试试改代码:

if (imageFile.exists() && imageFile.canRead()) {
    Log.d(TAG, "File exists");
    // 这里传imageFile而非字符串路径
    Glide.with(context)
         .load(imageFile)
         .into(foodImage);
}

二、实现图片上传到指定目录并通过Glide加载

你想让姑姑上传图片到/sdcard/Pictures/Recipes/,可以分两步来做:

1. 选择图片并复制到目标目录

先让用户从相册或相机选图,然后把选中的图片复制到你的Recipes目录里,还要生成唯一文件名避免重复:

// 假设你已经通过Intent拿到了选中图片的Uri(比如从相册选择)
private void saveImageToRecipesDir(Uri selectedImageUri) {
    try {
        InputStream inputStream = getContentResolver().openInputStream(selectedImageUri);
        File recipesDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Recipes");
        if (!recipesDir.exists()) {
            recipesDir.mkdirs();
        }
        // 生成唯一文件名,用时间戳避免重复
        String uniqueFileName = "recipe_" + System.currentTimeMillis() + ".jpg";
        File targetFile = new File(recipesDir, uniqueFileName);
        
        // 复制图片内容到目标文件
        OutputStream outputStream = new FileOutputStream(targetFile);
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        
        // 关闭流
        inputStream.close();
        outputStream.close();
        
        // 把这个uniqueFileName存到SQLite数据库里
        saveRecipeInfoToDb(uniqueFileName, "胡萝卜蛋糕", ...); // 你的菜谱信息保存逻辑
        
        // 用Glide加载刚保存的图片
        Glide.with(this)
             .load(targetFile)
             .placeholder(R.drawable.default_recipe) // 加个占位图更友好
             .error(R.drawable.load_error) // 加载失败显示错误图
             .into(foodImage);
    } catch (IOException e) {
        e.printStackTrace();
        // 这里可以给用户弹个Toast提示保存失败
    }
}

2. 从数据库读文件名加载图片

之后从SQLite取出文件名,按正确方式构建File对象,再用Glide加载:

// 从数据库获取对应菜谱的图片文件名
String imageFileName = getImageFileNameFromDb(recipeId);
File recipesDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Recipes");
File imageFile = new File(recipesDir, imageFileName);

if (imageFile.exists() && imageFile.canRead()) {
    Glide.with(context)
         .load(imageFile)
         .placeholder(R.drawable.default_recipe)
         .error(R.drawable.load_error)
         .into(foodImage);
} else {
    // 文件不存在的话,显示默认图
    foodImage.setImageResource(R.drawable.default_recipe);
}

额外小提示

  • 给Glide加占位图和错误图,用户体验会好很多
  • Android 13及以上,读取公共图片需要申请READ_MEDIA_IMAGES权限,代替原来的READ_EXTERNAL_STORAGE
  • 要是你的APP只需要自己的图片,也可以考虑用应用私有外部存储(getExternalFilesDir(Environment.DIRECTORY_PICTURES)),这种方式不需要申请存储权限,更安全合规

内容的提问来源于stack exchange,提问作者HemmaRoyD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:28:00