视图控件与全局位图缓存类优先调整。

This commit is contained in:
2025-12-11 19:18:02 +08:00
parent 2c77bf775b
commit f240d9c057
3 changed files with 71 additions and 21 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Dec 11 10:46:09 GMT 2025 #Thu Dec 11 11:14:29 GMT 2025
stageCount=15 stageCount=15
libraryProject= libraryProject=
baseVersion=15.12 baseVersion=15.12
publishVersion=15.12.14 publishVersion=15.12.14
buildCount=26 buildCount=28
baseBetaVersion=15.12.15 baseBetaVersion=15.12.15

View File

@@ -50,7 +50,7 @@ public class BitmapCacheUtils {
/** /**
* 核心接口:根据图片路径缓存 Bitmap 到内存 * 核心接口:根据图片路径缓存 Bitmap 到内存
* @param imagePath 图片绝对路径 * @param imagePath 图片绝对路径
* @return 缓存成功的 Bitmap / null路径无效/文件不存在) * @return 缓存成功的 Bitmap / null路径无效/文件不存在/解码失败
*/ */
public Bitmap cacheBitmap(String imagePath) { public Bitmap cacheBitmap(String imagePath) {
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
@@ -59,15 +59,23 @@ public class BitmapCacheUtils {
} }
File imageFile = new File(imagePath); File imageFile = new File(imagePath);
if (!imageFile.exists() || !imageFile.isFile()) { if (!imageFile.exists() || !imageFile.isFile() || imageFile.length() <= 0) {
LogUtils.e(TAG, "cacheBitmap: 图片文件不存在 - " + imagePath); LogUtils.e(TAG, "cacheBitmap: 图片文件无效(不存在/非文件/空文件) - " + imagePath);
return null; return null;
} }
// 已缓存则直接返回,避免重复加载 // 已缓存则直接返回,避免重复加载
if (mBitmapCacheMap.containsKey(imagePath)) { if (mBitmapCacheMap.containsKey(imagePath)) {
LogUtils.d(TAG, "cacheBitmap: 图片已缓存,直接返回 - " + imagePath); Bitmap cachedBitmap = mBitmapCacheMap.get(imagePath);
return mBitmapCacheMap.get(imagePath); // 额外校验缓存的Bitmap是否有效
if (cachedBitmap != null && !cachedBitmap.isRecycled()) {
LogUtils.d(TAG, "cacheBitmap: 图片已缓存,直接返回 - " + imagePath);
return cachedBitmap;
} else {
// 缓存的Bitmap已失效移除后重新加载
mBitmapCacheMap.remove(imagePath);
LogUtils.w(TAG, "cacheBitmap: 缓存Bitmap已失效移除后重新加载 - " + imagePath);
}
} }
// 压缩加载 Bitmap避免OOM // 压缩加载 Bitmap避免OOM
@@ -85,25 +93,33 @@ public class BitmapCacheUtils {
/** /**
* 核心接口:根据路径获取缓存的 Bitmap * 核心接口:根据路径获取缓存的 Bitmap
* @param imagePath 图片绝对路径 * @param imagePath 图片绝对路径
* @return 缓存的 Bitmap / null * @return 缓存的有效 Bitmap / null(未缓存/已回收)
*/ */
public Bitmap getCachedBitmap(String imagePath) { public Bitmap getCachedBitmap(String imagePath) {
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
return null; return null;
} }
return mBitmapCacheMap.get(imagePath); Bitmap bitmap = mBitmapCacheMap.get(imagePath);
// 校验Bitmap是否有效
if (bitmap != null && bitmap.isRecycled()) {
mBitmapCacheMap.remove(imagePath);
return null;
}
return bitmap;
} }
/** /**
* 清空所有 Bitmap 缓存(释放内存) * 清空所有 Bitmap 缓存(释放内存)
*/ */
public void clearAllCache() { public void clearAllCache() {
for (Bitmap bitmap : mBitmapCacheMap.values()) { synchronized (mBitmapCacheMap) {
if (bitmap != null && !bitmap.isRecycled()) { for (Bitmap bitmap : mBitmapCacheMap.values()) {
bitmap.recycle(); // 主动回收 Bitmap if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle(); // 主动回收 Bitmap
}
} }
mBitmapCacheMap.clear();
} }
mBitmapCacheMap.clear();
LogUtils.d(TAG, "clearAllCache: 所有 Bitmap 缓存已清空"); LogUtils.d(TAG, "clearAllCache: 所有 Bitmap 缓存已清空");
} }
@@ -115,22 +131,39 @@ public class BitmapCacheUtils {
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
return; return;
} }
Bitmap bitmap = mBitmapCacheMap.remove(imagePath); synchronized (mBitmapCacheMap) {
if (bitmap != null && !bitmap.isRecycled()) { Bitmap bitmap = mBitmapCacheMap.remove(imagePath);
bitmap.recycle(); if (bitmap != null && !bitmap.isRecycled()) {
LogUtils.d(TAG, "removeCachedBitmap: 移除并回收缓存 - " + imagePath); bitmap.recycle();
LogUtils.d(TAG, "removeCachedBitmap: 移除并回收缓存 - " + imagePath);
}
} }
} }
/** /**
* 压缩解码 Bitmap按最大尺寸缩放避免OOM * 压缩解码 Bitmap按最大尺寸缩放避免OOM
* @param imagePath 图片绝对路径
* @return 解码后的 Bitmap / null文件无效/解码失败)
*/ */
private Bitmap decodeCompressedBitmap(String imagePath) { private Bitmap decodeCompressedBitmap(String imagePath) {
// 前置校验:确保文件有效
File imageFile = new File(imagePath);
if (!imageFile.exists() || !imageFile.isFile() || imageFile.length() <= 0) {
LogUtils.e(TAG, "decodeCompressedBitmap: 文件无效,跳过解码 - " + imagePath);
return null;
}
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
// 第一步:只获取图片尺寸,不加载像素 // 第一步:只获取图片尺寸,不加载像素
options.inJustDecodeBounds = true; options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options); BitmapFactory.decodeFile(imagePath, options);
// 校验尺寸是否有效
if (options.outWidth <= 0 || options.outHeight <= 0) {
LogUtils.e(TAG, "decodeCompressedBitmap: 图片尺寸无效 - " + imagePath);
return null;
}
// 计算缩放比例 // 计算缩放比例
int sampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT); int sampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
@@ -141,7 +174,15 @@ public class BitmapCacheUtils {
options.inPurgeable = true; options.inPurgeable = true;
options.inInputShareable = true; options.inInputShareable = true;
return BitmapFactory.decodeFile(imagePath, options); try {
return BitmapFactory.decodeFile(imagePath, options);
} catch (OutOfMemoryError e) {
LogUtils.e(TAG, "decodeCompressedBitmap: OOM异常 - " + imagePath);
return null;
} catch (Exception e) {
LogUtils.e(TAG, "decodeCompressedBitmap: 解码异常 - " + imagePath, e);
return null;
}
} }
/** /**

View File

@@ -117,7 +117,7 @@ public class BackgroundView extends RelativeLayout {
// ====================================== 对外方法 ====================================== // ====================================== 对外方法 ======================================
/** /**
* 改造后:添加路径判断,路径更新时同步更新缓存 * 改造后:添加路径判断,路径更新时同步更新缓存缓存Bitmap为null时提示并加载透明背景
* @param imagePath 图片绝对路径 * @param imagePath 图片绝对路径
*/ */
public void loadImage(String imagePath) { public void loadImage(String imagePath) {
@@ -139,8 +139,8 @@ public class BackgroundView extends RelativeLayout {
// ======================== 新增:路径判断逻辑 ======================== // ======================== 新增:路径判断逻辑 ========================
// 1. 路径未变化:直接使用缓存 // 1. 路径未变化:直接使用缓存
if (imagePath.equals(mCurrentCachedPath)) { if (imagePath.equals(mCurrentCachedPath)) {
//ToastUtils.show("isReload == false");
Bitmap cachedBitmap = App._mBitmapCacheUtils.getCachedBitmap(imagePath); Bitmap cachedBitmap = App._mBitmapCacheUtils.getCachedBitmap(imagePath);
// 核心修改判断缓存Bitmap是否为null
if (cachedBitmap != null && !cachedBitmap.isRecycled()) { if (cachedBitmap != null && !cachedBitmap.isRecycled()) {
LogUtils.d(TAG, "loadImage: 路径未变,使用缓存 Bitmap"); LogUtils.d(TAG, "loadImage: 路径未变,使用缓存 Bitmap");
mImageAspectRatio = (float) cachedBitmap.getWidth() / cachedBitmap.getHeight(); mImageAspectRatio = (float) cachedBitmap.getWidth() / cachedBitmap.getHeight();
@@ -148,7 +148,13 @@ public class BackgroundView extends RelativeLayout {
adjustImageViewSize(); adjustImageViewSize();
mIvBackground.setVisibility(View.VISIBLE); mIvBackground.setVisibility(View.VISIBLE);
return; return;
} } else {
// 缓存Bitmap为空或已回收提示并加载透明背景
LogUtils.e(TAG, "loadImage: 全局位图缓存为空或已回收 - " + imagePath);
ToastUtils.show("全局位图缓存为空,无法加载图片");
setDefaultTransparentBackground();
return;
}
} }
// 2. 路径已更新:移除旧缓存,加载新图片并更新缓存 // 2. 路径已更新:移除旧缓存,加载新图片并更新缓存
@@ -166,6 +172,8 @@ public class BackgroundView extends RelativeLayout {
Bitmap bitmap = decodeBitmapWithCompress(imageFile, 1080, 1920); Bitmap bitmap = decodeBitmapWithCompress(imageFile, 1080, 1920);
if (bitmap == null) { if (bitmap == null) {
LogUtils.e(TAG, "loadImage: 图片解码失败");
ToastUtils.show("图片解码失败,无法加载");
setDefaultTransparentBackground(); setDefaultTransparentBackground();
return; return;
} }
@@ -258,6 +266,7 @@ public class BackgroundView extends RelativeLayout {
mImageAspectRatio = 1.0f; mImageAspectRatio = 1.0f;
// 清空缓存路径记录 // 清空缓存路径记录
mCurrentCachedPath = ""; mCurrentCachedPath = "";
mIvBackground.setVisibility(View.GONE);
} }
// ====================================== 重写方法 ====================================== // ====================================== 重写方法 ======================================