Files
HouseProperty/Glide错误处理方案.txt
renjianbo 39f1da9ca0 a
2026-01-09 16:09:42 +08:00

420 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> 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<Drawable> 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<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
if (e != null) {
Log.e("NineImageLoader", "九宫格图片加载失败: " + url, e);
}
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> 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<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
if (e != null) {
Log.e("DiscoveryFragment", "头像加载失败: " + discoveryListEntity.getAvatar(), e);
}
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> 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 {
<init>(...);
}
-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<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
if (e != null) {
Log.e(TAG, "图片加载失败: " + url, e);
// 可以在这里添加错误上报
}
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> 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);
}
```
## 常见错误处理
### 错误1DecodeJob异常
- **原因**:图片解码失败
- **解决**添加错误占位图验证URL有效性
### 错误2内存溢出
- **原因**:加载过大图片
- **解决**使用override()限制图片尺寸
### 错误3网络图片加载失败
- **原因**网络问题或URL无效
- **解决**:添加网络检查,使用错误占位图
## 测试验证
1. **测试正常图片加载**
- 验证占位图显示
- 验证图片加载成功
2. **测试错误情况**
- 无效URL
- 网络断开
- 损坏图片
3. **测试内存**
- 加载大量图片
- 检查内存使用
---
**Glide版本**: 4.9.0
**建议升级**: 考虑升级到Glide 4.16.0+(如果兼容)