From 328f559d2e85b938fb0c803d5818fb1649fad98c Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Sat, 20 Dec 2025 18:40:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E8=83=8C=E6=99=AF=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E4=BD=8D=E5=9B=BE=E7=BC=93=E5=AD=98=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- powerbell/build.properties | 4 +- .../java/cc/winboll/studio/powerbell/App.java | 9 +- .../powerbell/utils/BitmapCacheUtils.java | 89 +++++++++++++++++-- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/powerbell/build.properties b/powerbell/build.properties index 6f65874..71d4577 100644 --- a/powerbell/build.properties +++ b/powerbell/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sat Dec 20 09:38:35 GMT 2025 +#Sat Dec 20 10:26:46 GMT 2025 stageCount=10 libraryProject= baseVersion=15.14 publishVersion=15.14.9 -buildCount=76 +buildCount=81 baseBetaVersion=15.14.10 diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/App.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/App.java index cbdef5e..b51f7e3 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/App.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/App.java @@ -130,10 +130,11 @@ public class App extends GlobalApplication { public void onTerminate() { super.onTerminate(); ToastUtils.release(); - // 可选:App 终止时清空 Bitmap 缓存,释放内存 - if (_mBitmapCacheUtils != null) { - _mBitmapCacheUtils.clearAllCache(); - } } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + } } diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BitmapCacheUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BitmapCacheUtils.java index 0b6d024..e3bd087 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BitmapCacheUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BitmapCacheUtils.java @@ -1,21 +1,22 @@ package cc.winboll.studio.powerbell.utils; +import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.text.TextUtils; - +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.powerbell.App; import java.io.File; import java.util.HashMap; import java.util.Map; -import cc.winboll.studio.libappbase.LogUtils; - /** * @Author ZhanGSKen&豆包大模型 * @Date 2025/12/11 01:57 * @Describe 单例 Bitmap 缓存工具类(Java 7 兼容) - * 功能:内存缓存 Bitmap,支持路径关联缓存、全局获取、缓存清空 - * 特点:1. 单例模式 2. 压缩加载避免OOM 3. 路径- Bitmap 映射 4. 线程安全 + * 功能:内存缓存 Bitmap,支持路径关联缓存、全局获取、缓存清空、SP 持久化最后缓存路径、构造时预加载 + * 特点:1. 单例模式 2. 压缩加载避免OOM 3. 路径-Bitmap 映射 4. 线程安全 5. SP 持久化最后缓存路径 6. 构造时预加载 */ public class BitmapCacheUtils { public static final String TAG = "BitmapCacheUtils"; @@ -23,14 +24,24 @@ public class BitmapCacheUtils { private static final int MAX_WIDTH = 1080; private static final int MAX_HEIGHT = 1920; + // SP 相关常量 + private static final String SP_NAME = "BitmapCacheSP"; + private static final String SP_KEY_LAST_CACHE_PATH = "last_cache_image_path"; + // 单例实例(volatile 保证多线程可见性) private static volatile BitmapCacheUtils sInstance; // 路径-Bitmap 缓存容器(内存缓存) private final Map mBitmapCacheMap; + // SP 实例(用于持久化最后缓存路径) + private final SharedPreferences mSp; // 私有构造器(单例模式) private BitmapCacheUtils() { mBitmapCacheMap = new HashMap<>(); + // 初始化 SP(使用 App 全局上下文,避免内存泄漏) + mSp = App.getInstance().getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + // 构造时自动预加载 SP 中保存的最后一次缓存路径的图片 + preloadLastCachedBitmap(); } /** @@ -48,7 +59,7 @@ public class BitmapCacheUtils { } /** - * 核心接口:根据图片路径缓存 Bitmap 到内存 + * 核心接口:根据图片路径缓存 Bitmap 到内存,并持久化路径到 SP * @param imagePath 图片绝对路径 * @return 缓存成功的 Bitmap / null(路径无效/文件不存在/解码失败) */ @@ -70,6 +81,8 @@ public class BitmapCacheUtils { // 额外校验缓存的Bitmap是否有效 if (cachedBitmap != null && !cachedBitmap.isRecycled()) { LogUtils.d(TAG, "cacheBitmap: 图片已缓存,直接返回 - " + imagePath); + // 持久化当前路径到 SP(更新最后缓存路径) + saveLastCachePathToSp(imagePath); return cachedBitmap; } else { // 缓存的Bitmap已失效,移除后重新加载 @@ -83,7 +96,9 @@ public class BitmapCacheUtils { if (bitmap != null) { // 存入缓存容器 mBitmapCacheMap.put(imagePath, bitmap); - LogUtils.d(TAG, "cacheBitmap: 图片缓存成功 - " + imagePath); + // 持久化当前路径到 SP(更新最后缓存路径) + saveLastCachePathToSp(imagePath); + LogUtils.d(TAG, "cacheBitmap: 图片缓存成功并持久化路径 - " + imagePath); } else { LogUtils.e(TAG, "cacheBitmap: 图片解码失败 - " + imagePath); } @@ -109,7 +124,7 @@ public class BitmapCacheUtils { } /** - * 清空所有 Bitmap 缓存(释放内存) + * 清空所有 Bitmap 缓存(释放内存),并清空 SP 中保存的最后缓存路径 */ public void clearAllCache() { synchronized (mBitmapCacheMap) { @@ -120,7 +135,9 @@ public class BitmapCacheUtils { } mBitmapCacheMap.clear(); } - LogUtils.d(TAG, "clearAllCache: 所有 Bitmap 缓存已清空"); + // 清空 SP 中保存的最后缓存路径 + clearLastCachePathInSp(); + LogUtils.d(TAG, "clearAllCache: 所有 Bitmap 缓存已清空,SP 路径已清除"); } /** @@ -137,6 +154,12 @@ public class BitmapCacheUtils { bitmap.recycle(); LogUtils.d(TAG, "removeCachedBitmap: 移除并回收缓存 - " + imagePath); } + // 若移除的是最后缓存的路径,清空 SP + String lastPath = getLastCachePathFromSp(); + if (imagePath.equals(lastPath)) { + clearLastCachePathInSp(); + LogUtils.d(TAG, "removeCachedBitmap: 移除的是最后缓存路径,已清空 SP"); + } } } @@ -202,5 +225,53 @@ public class BitmapCacheUtils { } return inSampleSize; } + + /** + * 从 SP 中获取最后一次缓存的图片路径 + * @return 最后缓存的路径 / null(未保存) + */ + private String getLastCachePathFromSp() { + return mSp.getString(SP_KEY_LAST_CACHE_PATH, null); + } + + /** + * 将当前缓存路径持久化到 SP + * @param imagePath 图片绝对路径 + */ + private void saveLastCachePathToSp(String imagePath) { + if (TextUtils.isEmpty(imagePath)) { + return; + } + mSp.edit().putString(SP_KEY_LAST_CACHE_PATH, imagePath).commit(); // Java 7 兼容,使用 commit 而非 apply + LogUtils.d(TAG, "saveLastCachePathToSp: 持久化最后缓存路径 - " + imagePath); + } + + /** + * 清空 SP 中保存的最后缓存路径 + */ + private void clearLastCachePathInSp() { + mSp.edit().remove(SP_KEY_LAST_CACHE_PATH).commit(); + LogUtils.d(TAG, "clearLastCachePathInSp: SP 中最后缓存路径已清空"); + } + + /** + * 构造时预加载 SP 中保存的最后一次缓存路径的图片 + */ + private void preloadLastCachedBitmap() { + String lastPath = getLastCachePathFromSp(); + if (TextUtils.isEmpty(lastPath)) { + LogUtils.d(TAG, "preloadLastCachedBitmap: SP 中无保存的缓存路径,跳过预加载"); + return; + } + // 调用 cacheBitmap 预加载(内部已做文件校验和缓存判断) + Bitmap bitmap = cacheBitmap(lastPath); + if (bitmap != null) { + LogUtils.d(TAG, "preloadLastCachedBitmap: 预加载 SP 中最后缓存路径成功 - " + lastPath); + } else { + LogUtils.w(TAG, "preloadLastCachedBitmap: 预加载 SP 中最后缓存路径失败,清空无效路径 - " + lastPath); + // 预加载失败,清空 SP 中无效路径 + clearLastCachePathInSp(); + } + } }