添加应用内存整理后重新缓存位图的功能。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sat Dec 20 22:59:40 HKT 2025
|
||||
#Sun Dec 21 01:13:54 GMT 2025
|
||||
stageCount=13
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.12
|
||||
buildCount=0
|
||||
buildCount=18
|
||||
baseBetaVersion=15.14.13
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cc.winboll.studio.powerbell;
|
||||
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
@@ -9,11 +10,13 @@ import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
|
||||
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
||||
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import java.io.File;
|
||||
|
||||
public class App extends GlobalApplication {
|
||||
@@ -26,14 +29,20 @@ public class App extends GlobalApplication {
|
||||
public static final String ACTION_SWITCHTO_CN1 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN1";
|
||||
public static final String ACTION_SWITCHTO_CN2 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN2";
|
||||
|
||||
// 内存紧张通知常量
|
||||
private static final String TRIM_MEMORY_NOTIFY_TITLE = "应用使用时内存紧张提醒";
|
||||
private static final String TRIM_MEMORY_NOTIFY_CONTENT = "由于本应用使用时,系统通知内存紧张程度级别较高,图片缓存功能暂时不启用。";
|
||||
|
||||
// 数据配置存储工具
|
||||
static AppConfigUtils _mAppConfigUtils;
|
||||
static AppCacheUtils _mAppCacheUtils;
|
||||
// 新增:全局 Bitmap 缓存工具(常驻内存)
|
||||
// 全局 Bitmap 缓存工具(常驻内存)
|
||||
public static BitmapCacheUtils _mBitmapCacheUtils;
|
||||
|
||||
GlobalApplicationReceiver mReceiver;
|
||||
static String szTempDir = "";
|
||||
// 通知工具类实例(用于发送内存紧张通知)
|
||||
private NotificationManagerUtils mNotificationManager;
|
||||
|
||||
public static String getTempDirPath() {
|
||||
return szTempDir;
|
||||
@@ -60,13 +69,17 @@ public class App extends GlobalApplication {
|
||||
// 设置数据配置存储工具
|
||||
_mAppConfigUtils = getAppConfigUtils(this);
|
||||
_mAppCacheUtils = getAppCacheUtils(this);
|
||||
// 初始化全局 Bitmap 缓存工具(关键:App 启动时初始化,常驻内存)
|
||||
// 初始化全局 Bitmap 缓存工具
|
||||
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||
|
||||
// 初始化通知工具类(使用整理后的 NotificationManagerUtils)
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "onCreate: 通知工具类初始化完成");
|
||||
|
||||
mReceiver = new GlobalApplicationReceiver(this);
|
||||
mReceiver.registerAction();
|
||||
|
||||
// ======================== 新增:异步预加载背景图 ========================
|
||||
// 异步预加载背景图(保持原有逻辑)
|
||||
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -74,23 +87,19 @@ public class App extends GlobalApplication {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// 1. 获取背景源工具类实例
|
||||
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(App.this);
|
||||
if (bgSourceUtils == null) {
|
||||
LogUtils.e(TAG, "preloadBitmap: BackgroundSourceUtils 实例为空");
|
||||
return;
|
||||
}
|
||||
// 2. 获取当前背景Bean
|
||||
BackgroundBean bgBean = bgSourceUtils.getCurrentBackgroundBean();
|
||||
if (bgBean == null || !bgBean.isUseBackgroundFile()) {
|
||||
LogUtils.d(TAG, "preloadBitmap: 无有效背景文件,跳过预加载");
|
||||
return;
|
||||
}
|
||||
// 3. 获取背景图路径(优先取压缩图路径)
|
||||
String bgPath = bgBean.isUseBackgroundScaledCompressFile()
|
||||
? bgBean.getBackgroundScaledCompressFilePath()
|
||||
: bgBean.getBackgroundFilePath();
|
||||
// 4. 预加载到全局缓存
|
||||
if (_mBitmapCacheUtils != null) {
|
||||
_mBitmapCacheUtils.cacheBitmap(bgPath);
|
||||
LogUtils.d(TAG, "preloadBitmap: 应用启动时预加载成功 - " + bgPath);
|
||||
@@ -103,8 +112,7 @@ public class App extends GlobalApplication {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}, 1000); // 延迟1秒执行,避免阻塞应用初始化
|
||||
// ======================== 预加载逻辑结束 ========================
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 保持原有方法不变
|
||||
@@ -130,11 +138,91 @@ public class App extends GlobalApplication {
|
||||
public void onTerminate() {
|
||||
super.onTerminate();
|
||||
ToastUtils.release();
|
||||
// 释放通知工具类资源,避免内存泄漏
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.release();
|
||||
mNotificationManager = null;
|
||||
LogUtils.d(TAG, "onTerminate: 通知工具类资源已释放");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
LogUtils.d(TAG, "onTrimMemory: 内存等级变化 | level=" + getTrimMemoryLevelDesc(level));
|
||||
|
||||
// 仅在中等及以上内存紧张等级发送通知,避免频繁打扰
|
||||
if (mNotificationManager == null) {
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
}
|
||||
if (level > ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
|
||||
sendTrimMemoryNotification(level);
|
||||
} else {
|
||||
// 再次缓存 Bitmap 缓存工具
|
||||
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||
LogUtils.d(TAG, "Bitmap 缓存启用中。");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送内存紧张通知(完全复用 NotificationManagerUtils 的 showRemindNotification 方法)
|
||||
*/
|
||||
private void sendTrimMemoryNotification(int level) {
|
||||
LogUtils.d(TAG, "sendTrimMemoryNotification: 准备发送内存紧张通知");
|
||||
// 构建通知消息体
|
||||
NotificationMessage message = new NotificationMessage();
|
||||
message.setTitle(TRIM_MEMORY_NOTIFY_TITLE);
|
||||
message.setContent(String.format("%s [ 缓存紧张级别描述: Level %d | %s ]",TRIM_MEMORY_NOTIFY_CONTENT, level, getTrimMemoryLevelDesc(level)));
|
||||
// 使用整理后的 NotificationManagerUtils 发送通知(复用提醒渠道配置)
|
||||
mNotificationManager.showConfigNotification(this, message);
|
||||
LogUtils.d(TAG, "sendTrimMemoryNotification: 通知已通过 NotificationManagerUtils 发送");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换内存等级为可读描述,便于日志调试
|
||||
* 排序规则:按 ComponentCallbacks2 枚举数值从高到低排列(数值越高,内存越紧张)
|
||||
*/
|
||||
/**
|
||||
* 转换内存等级为可读描述,便于日志调试
|
||||
* 排序规则:按 ComponentCallbacks2 枚举实际数值(10进制)从高到低排列
|
||||
* 数值来源:接口中定义的 16进制(注释10进制)数值
|
||||
*/
|
||||
private String getTrimMemoryLevelDesc(int level) {
|
||||
switch (level) {
|
||||
// 数值 80(0x50):应用内存完全紧张(补充接口中实际存在的枚举项)
|
||||
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
|
||||
return "TRIM_MEMORY_COMPLETE(应用内存完全紧张)";
|
||||
// 数值 60(0x3c):中等内存紧张
|
||||
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
|
||||
return "MODERATE(中等内存紧张)";
|
||||
// 数值 40(0x28):应用进入后台
|
||||
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
|
||||
return "BACKGROUND(应用进入后台)";
|
||||
// 数值 20(0x14):应用UI隐藏
|
||||
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
|
||||
return "BACKGROUND(应用UI隐藏)";
|
||||
// 数值 15(0xf):应用运行时关键级紧张
|
||||
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
|
||||
return "RUNNING_CRITICAL(应用运行关键级紧张)";
|
||||
// 数值 10(0xa):应用运行时低内存
|
||||
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
|
||||
return "RUNNING_LOW(应用运行低内存)";
|
||||
// 数值 5(0x5):应用运行时中等紧张
|
||||
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
|
||||
return "RUNNING_MODERATE(应用运行中等内存紧张)";
|
||||
|
||||
// 以下为注释备用项(接口中未提供,按你的原有注释保留)
|
||||
// 数值 100:内存极度紧张(系统可能强制杀死应用)
|
||||
// case ComponentCallbacks2.TRIM_MEMORY_URGENT:
|
||||
// return "URGENT(内存极度紧张)";
|
||||
// 数值 20:用户正在离开应用(如按Home键)
|
||||
// case ComponentCallbacks2.TRIM_MEMORY_USER_LEAVING:
|
||||
// return "USER_LEAVING(用户正在离开应用)";
|
||||
|
||||
// 未知等级
|
||||
default:
|
||||
return "UNKNOWN(" + level + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
|
||||
/**
|
||||
* 通知工具类:统一管理前台服务/电池提醒通知
|
||||
* 通知工具类:统一管理前台服务/电池提醒/应用配置信息通知
|
||||
* 适配:API19-30 | Java7 | 小米手机
|
||||
* 特性:前台服务无铃声、提醒通知系统默认铃声、API分级适配、内存泄漏防护
|
||||
* 特性:前台服务无铃声、提醒通知系统默认铃声、配置通知低优先级无打扰、API分级适配、内存泄漏防护
|
||||
*/
|
||||
public class NotificationManagerUtils {
|
||||
// ================================== 静态常量(置顶统一管理,杜绝魔法值)=================================
|
||||
@@ -30,9 +30,11 @@ public class NotificationManagerUtils {
|
||||
// 通知渠道ID(API26+ 必需,区分通知类型)
|
||||
public static final String CHANNEL_ID_FOREGROUND = "cc.winboll.studio.powerbell.channel.foreground";
|
||||
public static final String CHANNEL_ID_REMIND = "cc.winboll.studio.powerbell.channel.remind";
|
||||
public static final String CHANNEL_ID_CONFIG = "cc.winboll.studio.powerbell.channel.config"; // 新增:应用配置信息渠道
|
||||
// 通知ID(唯一标识,避免重复)
|
||||
public static final int NOTIFY_ID_FOREGROUND_SERVICE = 1001;
|
||||
public static final int NOTIFY_ID_REMIND = 1002;
|
||||
public static final int NOTIFY_ID_CONFIG = 1003; // 新增:应用配置信息通知ID
|
||||
// 低版本兼容:默认通知图标(API<21 避免显示异常)
|
||||
private static final int NOTIFICATION_DEFAULT_ICON = R.drawable.ic_launcher;
|
||||
// 通知内容兜底常量
|
||||
@@ -40,9 +42,12 @@ public class NotificationManagerUtils {
|
||||
private static final String FOREGROUND_NOTIFY_CONTENT_DEFAULT = "后台监测电池状态";
|
||||
private static final String REMIND_NOTIFY_TITLE_DEFAULT = "电池状态提醒";
|
||||
private static final String REMIND_NOTIFY_CONTENT_DEFAULT = "电池状态异常,请及时处理";
|
||||
private static final String CONFIG_NOTIFY_TITLE_DEFAULT = "应用配置更新"; // 新增:配置通知默认标题
|
||||
private static final String CONFIG_NOTIFY_CONTENT_DEFAULT = "配置信息已更新,生效中"; // 新增:配置通知默认内容
|
||||
// PendingIntent请求码
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_FOREGROUND = 0;
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_REMIND = 1;
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_CONFIG = 2; // 新增:配置通知请求码
|
||||
|
||||
// ================================== 成员变量(私有封装,按依赖优先级排序)=================================
|
||||
// 核心上下文(应用级,避免内存泄漏)
|
||||
@@ -71,7 +76,7 @@ public class NotificationManagerUtils {
|
||||
|
||||
// ================================== 核心初始化方法(通知渠道,API分级适配)=================================
|
||||
/**
|
||||
* 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动)
|
||||
* 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动)、配置信息渠道(低优先级无打扰)
|
||||
*/
|
||||
private void initNotificationChannels() {
|
||||
LogUtils.d(TAG, "initNotificationChannels: 执行通知渠道初始化");
|
||||
@@ -114,10 +119,25 @@ public class NotificationManagerUtils {
|
||||
remindChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 电池提醒渠道配置完成");
|
||||
|
||||
// 3. 应用配置信息渠道(新增:最低优先级,无铃声无振动,仅提示不打扰)
|
||||
NotificationChannel configChannel = new NotificationChannel(
|
||||
CHANNEL_ID_CONFIG,
|
||||
"应用配置信息",
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
);
|
||||
configChannel.setDescription("应用配置更新、参数变更等提示,无声音、无振动");
|
||||
configChannel.enableLights(false);
|
||||
configChannel.enableVibration(false);
|
||||
configChannel.setSound(null, null);
|
||||
configChannel.setShowBadge(false);
|
||||
configChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 应用配置信息渠道配置完成");
|
||||
|
||||
// 注册渠道到系统
|
||||
mNotificationManager.createNotificationChannel(foregroundChannel);
|
||||
mNotificationManager.createNotificationChannel(remindChannel);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 成功:创建前台服务+电池提醒渠道");
|
||||
mNotificationManager.createNotificationChannel(configChannel); // 注册新增渠道
|
||||
LogUtils.d(TAG, "initNotificationChannels: 成功:创建前台服务+电池提醒+应用配置信息渠道");
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(前台服务通知:启动/更新/取消)=================================
|
||||
@@ -207,6 +227,31 @@ public class NotificationManagerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(应用配置信息通知:发送)=================================
|
||||
/**
|
||||
* 发送应用配置信息通知(新增:低优先级无铃声,仅提示不打扰)
|
||||
*/
|
||||
public void showConfigNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "showConfigNotification: 执行 | notifyId=" + NOTIFY_ID_CONFIG + " | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification configNotify = buildConfigNotification(context, message);
|
||||
if (configNotify == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_CONFIG, configNotify);
|
||||
LogUtils.d(TAG, "showConfigNotification: 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 对外工具方法(通知取消:单个/全部)=================================
|
||||
/**
|
||||
* 取消指定ID的通知
|
||||
@@ -349,6 +394,59 @@ public class NotificationManagerUtils {
|
||||
return notification;
|
||||
}
|
||||
|
||||
// ================================== 内部辅助方法(通知构建:应用配置信息通知)=================================
|
||||
/**
|
||||
* 构建应用配置信息通知(新增:全版本无铃声+无振动,低优先级)
|
||||
*/
|
||||
private Notification buildConfigNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildConfigNotification: 执行 | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null) {
|
||||
LogUtils.e(TAG, "buildConfigNotification: 失败:param is null | context=" + context + " | message=" + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : CONFIG_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : CONFIG_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildConfigNotification: 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// API26+:绑定配置渠道(渠道已配置无铃声)
|
||||
builder = new Notification.Builder(context, CHANNEL_ID_CONFIG);
|
||||
LogUtils.d(TAG, "buildConfigNotification: 使用API26+渠道构建");
|
||||
} else {
|
||||
// API<26:直接构建,手动禁用铃声振动
|
||||
builder = new Notification.Builder(context);
|
||||
builder.setSound(null);
|
||||
builder.setVibrate(new long[]{0});
|
||||
builder.setDefaults(0);
|
||||
LogUtils.d(TAG, "buildConfigNotification: 使用API<26手动配置");
|
||||
}
|
||||
|
||||
// 通用配置
|
||||
builder.setSmallIcon(NOTIFICATION_DEFAULT_ICON)
|
||||
.setContentTitle(title)
|
||||
.setContentText(content)
|
||||
.setAutoCancel(true) // 点击关闭
|
||||
.setOngoing(false)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(createJumpPendingIntent(context, PENDING_INTENT_REQUEST_CODE_CONFIG));
|
||||
|
||||
// API21+ 新增大图标+主题色
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
builder.setLargeIcon(getAppIcon(context))
|
||||
.setColor(context.getResources().getColor(R.color.colorPrimary))
|
||||
.setPriority(Notification.PRIORITY_MIN); // 最低优先级
|
||||
LogUtils.d(TAG, "buildConfigNotification: 补充API21+配置");
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
LogUtils.d(TAG, "buildConfigNotification: 成功构建配置信息通知");
|
||||
return notification;
|
||||
}
|
||||
|
||||
// ================================== 内部辅助方法(创建跳转PendingIntent,API30安全适配)=================================
|
||||
/**
|
||||
* 创建跳转MainActivity的PendingIntent,API23+ 添加IMMUTABLE标记(避免安全异常)
|
||||
|
||||
Reference in New Issue
Block a user