# Glide 图片加载错误处理方案 ## 错误信息 ``` at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) ``` ## 问题分析 ### 可能原因 1. **图片格式不支持或损坏** - 图片文件损坏 - 不支持的图片格式 - 图片编码异常 2. **内存不足** - 加载大图片时内存溢出 - 同时加载多张图片导致内存压力 3. **网络问题** - 网络图片下载不完整 - 响应数据格式错误 4. **Glide配置问题** - 缺少ProGuard规则 - Glide版本兼容性问题 5. **Context问题** - Activity/Fragment已销毁但仍在加载 - Context引用导致内存泄漏 ## 解决方案 ### 方案一:添加错误处理和占位图(推荐) #### 1. 优化 GlideEngine.java 在 `app/src/main/java/tools/GlideEngine.java` 中添加错误处理: ```java @Override public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { Glide.with(context) .load(url) .placeholder(R.drawable.picture_image_placeholder) // 添加占位图 .error(R.drawable.picture_image_placeholder) // 添加错误占位图 .fallback(R.drawable.picture_image_placeholder) // 添加空URL占位图 .skipMemoryCache(false) // 使用内存缓存 .diskCacheStrategy(DiskCacheStrategy.ALL) // 使用磁盘缓存 .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { // 记录错误日志 if (e != null) { Log.e("Glide", "图片加载失败: " + url, e); } return false; // 返回false让Glide显示error占位图 } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(imageView); } ``` #### 2. 优化 NineImageLoader.java 在 `app/src/main/java/utils/NineImageLoader.java` 中: ```java @Override public void onDisplayImage(Context context, ImageView imageView, String url) { RequestOptions requestOptions = new RequestOptions(); requestOptions.placeholder(R.mipmap.icon_default_rectangle); requestOptions.error(R.mipmap.icon_default_rectangle); requestOptions.skipMemoryCache(false); requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL); // 添加错误处理 Glide.with(context) .load(url) .apply(requestOptions) .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { if (e != null) { Log.e("NineImageLoader", "九宫格图片加载失败: " + url, e); } return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(imageView); } ``` #### 3. 优化 DiscoveryFragment.java 在 `app/src/main/java/com/sl/house_property/discovery/DiscoveryFragment.java` 中: ```java RequestOptions requestOptions = new RequestOptions(); requestOptions.placeholder(R.mipmap.icon_default_rectangle); requestOptions.error(R.mipmap.icon_default_rectangle); requestOptions.skipMemoryCache(false); requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL); Glide.with(getContext()) .load(discoveryListEntity.getAvatar()) .apply(requestOptions) .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { if (e != null) { Log.e("DiscoveryFragment", "头像加载失败: " + discoveryListEntity.getAvatar(), e); } return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(homeGridAdapterItemBinding.imageHead); ``` ### 方案二:添加ProGuard规则 在 `app/proguard-rules.pro` 中添加: ```proguard # Glide 图片加载库 -keep public class * implements com.bumptech.glide.module.GlideModule -keep class * extends com.bumptech.glide.module.AppGlideModule { (...); } -keep public class * implements com.bumptech.glide.module.RegisterGlideModule -keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { *** rewind(); } # Glide 注解 -keep class com.bumptech.glide.load.engine.DecodeJob { *; } -keep class com.bumptech.glide.load.engine.bitmap_recycle.** { *; } -keep class com.bumptech.glide.load.resource.bitmap.** { *; } # Glide 错误处理 -keep class com.bumptech.glide.load.engine.GlideException { *; } -keep class com.bumptech.glide.load.engine.GlideException$** { *; } ``` ### 方案三:配置Glide内存和缓存 在 `MyApplication.java` 中添加Glide配置: ```java @Override public void onCreate() { super.onCreate(); // ... 其他初始化代码 ... // 配置Glide configureGlide(); } private void configureGlide() { // 设置内存缓存大小(可选) // Glide默认会根据设备内存自动调整 } ``` ### 方案四:添加图片URL验证 在使用Glide加载图片前,先验证URL: ```java public static boolean isValidImageUrl(String url) { if (TextUtils.isEmpty(url)) { return false; } // 检查URL格式 if (!url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("file://") && !url.startsWith("content://")) { return false; } // 检查图片格式 String lowerUrl = url.toLowerCase(); return lowerUrl.endsWith(".jpg") || lowerUrl.endsWith(".jpeg") || lowerUrl.endsWith(".png") || lowerUrl.endsWith(".gif") || lowerUrl.endsWith(".webp") || lowerUrl.contains("image"); } ``` ## 完整优化示例 ### 创建统一的Glide工具类 创建文件:`app/src/main/java/utils/GlideUtils.java` ```java package utils; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.Log; import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; import com.sl.house_property.R; public class GlideUtils { private static final String TAG = "GlideUtils"; /** * 加载图片(带错误处理) */ public static void loadImage(Context context, String url, ImageView imageView) { loadImage(context, url, imageView, R.drawable.picture_image_placeholder); } /** * 加载图片(带错误处理和占位图) */ public static void loadImage(Context context, String url, ImageView imageView, int placeholderResId) { if (context == null || imageView == null) { Log.w(TAG, "Context或ImageView为空,无法加载图片"); return; } if (!isValidImageUrl(url)) { Log.w(TAG, "无效的图片URL: " + url); imageView.setImageResource(placeholderResId); return; } RequestOptions options = new RequestOptions() .placeholder(placeholderResId) .error(placeholderResId) .fallback(placeholderResId) .skipMemoryCache(false) .diskCacheStrategy(DiskCacheStrategy.ALL); Glide.with(context) .load(url) .apply(options) .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { if (e != null) { Log.e(TAG, "图片加载失败: " + url, e); // 可以在这里添加错误上报 } return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .into(imageView); } /** * 验证图片URL是否有效 */ private static boolean isValidImageUrl(String url) { if (url == null || url.trim().isEmpty()) { return false; } String lowerUrl = url.toLowerCase().trim(); return lowerUrl.startsWith("http://") || lowerUrl.startsWith("https://") || lowerUrl.startsWith("file://") || lowerUrl.startsWith("content://") || lowerUrl.startsWith("drawable://"); } /** * 加载圆形图片 */ public static void loadCircleImage(Context context, String url, ImageView imageView) { RequestOptions options = new RequestOptions() .circleCrop() .placeholder(R.drawable.picture_image_placeholder) .error(R.drawable.picture_image_placeholder); Glide.with(context) .load(url) .apply(options) .into(imageView); } /** * 清除Glide缓存 */ public static void clearCache(Context context) { Glide.get(context).clearMemory(); new Thread(new Runnable() { @Override public void run() { Glide.get(context).clearDiskCache(); } }).start(); } } ``` ## 使用建议 ### 1. 统一使用工具类 将所有Glide调用改为使用 `GlideUtils`: ```java // 替换前 Glide.with(context).load(url).into(imageView); // 替换后 GlideUtils.loadImage(context, url, imageView); ``` ### 2. 添加必要的导入 在使用RequestListener时需要添加: ```java import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; ``` ### 3. 检查Context生命周期 确保在Activity/Fragment销毁时取消Glide请求: ```java @Override protected void onDestroy() { super.onDestroy(); Glide.with(this).clear(imageView); } ``` ## 常见错误处理 ### 错误1:DecodeJob异常 - **原因**:图片解码失败 - **解决**:添加错误占位图,验证URL有效性 ### 错误2:内存溢出 - **原因**:加载过大图片 - **解决**:使用override()限制图片尺寸 ### 错误3:网络图片加载失败 - **原因**:网络问题或URL无效 - **解决**:添加网络检查,使用错误占位图 ## 测试验证 1. **测试正常图片加载** - 验证占位图显示 - 验证图片加载成功 2. **测试错误情况** - 无效URL - 网络断开 - 损坏图片 3. **测试内存** - 加载大量图片 - 检查内存使用 --- **Glide版本**: 4.9.0 **建议升级**: 考虑升级到Glide 4.16.0+(如果兼容)