广播消息分开为,电量消息与应用配置更新消息。
This commit is contained in:
@@ -505,7 +505,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
// ======================== 消息发送方法 ========================
|
||||
private void notifyServiceAppConfigChange() {
|
||||
LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更");
|
||||
ControlCenterService.updateStatus(this);
|
||||
ControlCenterService.sendAppConfigStatusUpdateMessage(this);
|
||||
reloadAppConfig();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,20 @@ public class ControlCenterServiceHandler extends Handler {
|
||||
private static final int BATTERY_LEVEL_MIN = 0;
|
||||
private static final int BATTERY_LEVEL_MAX = 100;
|
||||
|
||||
// 通知文案常量(抽离魔法值,便于统一修改)
|
||||
private static final String CHARGE_REMIND_TITLE = "充电提醒";
|
||||
private static final String USAGE_REMIND_TITLE = "耗电提醒";
|
||||
private static final String CHARGE_REMIND_CONTENT_FORMAT = "(+) 当前电量%d%%,%s,已达标建议及时断电,保护电池寿命~";
|
||||
private static final String USAGE_REMIND_CONTENT_FORMAT = "(-) 当前电量%d%%,%s,已偏低建议及时充电,避免设备关机~";
|
||||
private static final String CHARGE_STATE_CHARGING = "充电中";
|
||||
private static final String CHARGE_STATE_NOT_CHARGING = "未充电";
|
||||
|
||||
// ================================== 成员变量区(弱引用防泄漏,final保证不可变)=================================
|
||||
private final WeakReference<ControlCenterService> mwrControlCenterService;
|
||||
|
||||
// ================================== 构造方法(强制传入服务,初始化弱引用)=================================
|
||||
public ControlCenterServiceHandler(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "ControlCenterServiceHandler: 构造方法执行 | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
|
||||
LogUtils.d(TAG, "构造方法执行 | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
|
||||
this.mwrControlCenterService = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
@@ -89,21 +97,21 @@ public class ControlCenterServiceHandler extends Handler {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 构建通知模型,使用String.format统一格式
|
||||
// 2. 构建通知模型,使用统一格式
|
||||
NotificationMessage remindMsg = new NotificationMessage();
|
||||
String chargeStateDesc = isCharging ? "充电中" : "未充电";
|
||||
String chargeStateDesc = isCharging ? CHARGE_STATE_CHARGING : CHARGE_STATE_NOT_CHARGING;
|
||||
if (REMIND_TYPE_CHARGE.equals(remindType)) {
|
||||
remindMsg.setTitle("充电提醒");
|
||||
remindMsg.setContent(String.format("(+) 当前电量%d%%,%s,已达标建议及时断电,保护电池寿命~", currentBattery, chargeStateDesc));
|
||||
remindMsg.setTitle(CHARGE_REMIND_TITLE);
|
||||
remindMsg.setContent(String.format(CHARGE_REMIND_CONTENT_FORMAT, currentBattery, chargeStateDesc));
|
||||
remindMsg.setRemindMSG("charge_remind");
|
||||
} else {
|
||||
remindMsg.setTitle("耗电提醒");
|
||||
remindMsg.setContent(String.format("(-) 当前电量%d%%,%s,已偏低建议及时充电,避免设备关机~", currentBattery, chargeStateDesc));
|
||||
remindMsg.setTitle(USAGE_REMIND_TITLE);
|
||||
remindMsg.setContent(String.format(USAGE_REMIND_CONTENT_FORMAT, currentBattery, chargeStateDesc));
|
||||
remindMsg.setRemindMSG("usage_remind");
|
||||
}
|
||||
LogUtils.d(TAG, "handleRemindMessage: 通知模型构建完成 | title=" + remindMsg.getTitle() + " | content=" + remindMsg.getContent());
|
||||
|
||||
// 3. 直接调用通知工具类发送,不校验返回结果
|
||||
// 3. 调用通知工具类发送提醒
|
||||
LogUtils.d(TAG, "handleRemindMessage: 调用通知工具类发送提醒 | remindMSG=" + remindMsg.getRemindMSG());
|
||||
service.getNotificationManager().showRemindNotification(service, remindMsg);
|
||||
LogUtils.d(TAG, "handleRemindMessage: 提醒通知发送流程执行完毕");
|
||||
|
||||
@@ -14,11 +14,11 @@ import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/19 20:23
|
||||
* @Describe 控制中心广播接收器
|
||||
* 控制中心广播接收器
|
||||
* 功能:监听电池状态变化、前台通知更新、配置变更指令
|
||||
* 适配:Java7 | API30 | 内存泄漏防护 | 多线程状态同步
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/19 20:23
|
||||
*/
|
||||
public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
@@ -34,11 +34,13 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
private static final int BATTERY_LEVEL_MIN = 0;
|
||||
private static final int BATTERY_LEVEL_MAX = 100;
|
||||
|
||||
// ================================== 成员变量区(弱引用防泄漏,volatile保线程安全)=================================
|
||||
private WeakReference<ControlCenterService> mwrControlCenterService;
|
||||
// ================================== 静态状态标记(volatile保证多线程可见性)=================================
|
||||
private static volatile int sLastBatteryLevel = -1; // 上次电量(多线程可见)
|
||||
private static volatile boolean sIsCharging = false; // 上次充电状态(多线程可见)
|
||||
|
||||
// ================================== 成员变量区(弱引用防泄漏,按功能分层)=================================
|
||||
private WeakReference<ControlCenterService> mwrControlCenterService;
|
||||
|
||||
// ================================== 构造方法(初始化弱引用,避免服务强引用泄漏)=================================
|
||||
public ControlCenterServiceReceiver(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "构造接收器 | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
|
||||
@@ -48,18 +50,18 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// ================================== 广播核心接收逻辑(入口方法,分Action分发处理)=================================
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null"));
|
||||
LogUtils.d(TAG, "onReceive: 接收广播 | action=" + (intent != null ? intent.getAction() : "null"));
|
||||
|
||||
// 基础参数校验
|
||||
if (context == null || intent == null || intent.getAction() == null) {
|
||||
LogUtils.e(TAG, "onReceive: 参数无效,终止处理");
|
||||
LogUtils.e(TAG, "onReceive: 参数无效(context=" + context + " | intent=" + intent + "),终止处理");
|
||||
return;
|
||||
}
|
||||
|
||||
// 弱引用获取服务,双重校验服务有效性
|
||||
ControlCenterService service = mwrControlCenterService != null ? mwrControlCenterService.get() : null;
|
||||
if (service == null || service.isDestroyed()) {
|
||||
LogUtils.e(TAG, "onReceive: 服务已销毁或为空,注销广播");
|
||||
LogUtils.e(TAG, "onReceive: 服务已销毁或为空(service=" + service + "),注销广播");
|
||||
unregisterAction(context);
|
||||
return;
|
||||
}
|
||||
@@ -90,7 +92,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param intent 电池状态广播意图
|
||||
*/
|
||||
private void handleBatteryStateChanged(ControlCenterService service, Intent intent) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | service=" + service);
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | service=" + service + " | intent=" + intent);
|
||||
try {
|
||||
// 1. 解析并校验当前电池状态
|
||||
boolean currentCharging = BatteryUtils.isCharging(intent);
|
||||
@@ -104,19 +106,14 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 加载最新配置(三级兜底:本地配置→服务内存配置→默认配置)
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(service).loadAppConfig();
|
||||
// 3. 同步电池状态到服务,触发线程更新
|
||||
service.notifyBatteryStateChanged(currentCharging, currentBatteryLevel);
|
||||
|
||||
// 4. 同步电池状态到配置,通知服务更新线程
|
||||
latestConfig.setCurrentBatteryValue(currentBatteryLevel);
|
||||
latestConfig.setIsCharging(currentCharging);
|
||||
service.notifyAppConfigUpdate(latestConfig);
|
||||
|
||||
// 5. 更新静态缓存状态,保证多线程可见
|
||||
// 4. 更新静态缓存状态,保证多线程可见
|
||||
sIsCharging = currentCharging;
|
||||
sLastBatteryLevel = currentBatteryLevel;
|
||||
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功 | 缓存电量=" + sLastBatteryLevel + "% | 缓存充电状态=" + sIsCharging);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged: 处理失败", e);
|
||||
}
|
||||
@@ -131,7 +128,8 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
try {
|
||||
// 加载最新配置
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(service).loadAppConfig();
|
||||
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate: 加载最新配置 | 充电阈值=" + latestConfig.getChargeReminderValue() + " | 耗电阈值=" + latestConfig.getUsageReminderValue());
|
||||
|
||||
// 同步缓存的电池状态到配置
|
||||
latestConfig.setCurrentBatteryValue(sLastBatteryLevel);
|
||||
latestConfig.setIsCharging(sIsCharging);
|
||||
@@ -155,18 +153,17 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
|
||||
// 非空校验,避免空指针
|
||||
if (notifyUtils == null || notifyMsg == null) {
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification: 通知工具类或消息为空");
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification: 通知工具类或消息为空(notifyUtils=" + notifyUtils + " | notifyMsg=" + notifyMsg + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
notifyUtils.updateForegroundServiceNotify(notifyMsg);
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification: 前台通知更新成功");
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification: 前台通知更新成功 | 通知标题=" + notifyMsg.getTitle());
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification: 处理失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ================================== 广播注册/注销(强化容错,避免重复操作)=================================
|
||||
/**
|
||||
* 注册广播接收器
|
||||
@@ -190,7 +187,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
filter.setPriority(BROADCAST_PRIORITY);
|
||||
|
||||
context.registerReceiver(this, filter);
|
||||
LogUtils.d(TAG, "registerAction: 广播注册成功");
|
||||
LogUtils.d(TAG, "registerAction: 广播注册成功 | 优先级=" + BROADCAST_PRIORITY);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "registerAction: 注册失败", e);
|
||||
}
|
||||
@@ -227,11 +224,12 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
if (mwrControlCenterService != null) {
|
||||
mwrControlCenterService.clear();
|
||||
mwrControlCenterService = null;
|
||||
LogUtils.d(TAG, "release: 弱引用已清空");
|
||||
}
|
||||
// 重置静态状态缓存
|
||||
sLastBatteryLevel = -1;
|
||||
sIsCharging = false;
|
||||
LogUtils.d(TAG, "release: 资源释放完成");
|
||||
LogUtils.d(TAG, "release: 静态状态缓存已重置");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,11 +22,35 @@ public class AssistantService extends Service {
|
||||
private static final String TAG = "AssistantService";
|
||||
// 服务返回策略常量(统一定义,避免魔法值)
|
||||
private static final int SERVICE_RETURN_STICKY = START_STICKY;
|
||||
// 服务绑定标记常量
|
||||
private static final int BIND_FLAG = Context.BIND_IMPORTANT;
|
||||
|
||||
// ================================== 成员变量区(按功能分层,volatile保证多线程可见性)=================================
|
||||
private AppConfigUtils mAppConfigUtils;
|
||||
private MyServiceConnection mMyServiceConnection;
|
||||
private volatile boolean mIsThreadAlive;
|
||||
private AppConfigUtils mAppConfigUtils;
|
||||
|
||||
// ================================== 内部类(服务连接状态监听,前置定义便于引用)=================================
|
||||
/**
|
||||
* 服务连接状态监听器
|
||||
* 主服务连接成功时记录状态,断开时自动重连
|
||||
*/
|
||||
private class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
LogUtils.d(TAG, "onServiceConnected: 主服务连接成功 | 组件名=" + name.getClassName() + " | Binder=" + service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected: 主服务连接断开 | 组件名=" + name.getClassName());
|
||||
// 主服务断开且配置启用时,重新唤醒绑定
|
||||
if (mAppConfigUtils != null && mAppConfigUtils.isServiceEnabled()) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected: 配置启用,尝试重新唤醒并绑定主服务");
|
||||
wakeupAndBindMain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 服务生命周期方法(按执行顺序排列:onCreate→onStartCommand→onBind→onDestroy)=================================
|
||||
@Override
|
||||
@@ -56,7 +80,7 @@ public class AssistantService extends Service {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "onStartCommand: 守护服务触发重启 | intent=" + intent + " | flags=" + flags + " | startId=" + startId);
|
||||
LogUtils.d(TAG, "onStartCommand: 守护服务触发重启 | flags=" + flags + " | startId=" + startId);
|
||||
// 配置工具类为空时,直接返回非粘性策略
|
||||
if (mAppConfigUtils == null) {
|
||||
LogUtils.e(TAG, "onStartCommand: AppConfigUtils未初始化,终止服务");
|
||||
@@ -85,15 +109,7 @@ public class AssistantService extends Service {
|
||||
mIsThreadAlive = false;
|
||||
|
||||
// 解绑主服务,添加异常捕获防止重复解绑崩溃
|
||||
if (mMyServiceConnection != null) {
|
||||
try {
|
||||
unbindService(mMyServiceConnection);
|
||||
LogUtils.d(TAG, "onDestroy: 已成功解绑ControlCenterService");
|
||||
} catch (IllegalArgumentException e) {
|
||||
LogUtils.w(TAG, "onDestroy: 解绑服务失败,服务未绑定 | " + e.getMessage());
|
||||
}
|
||||
mMyServiceConnection = null;
|
||||
}
|
||||
unbindMainService();
|
||||
|
||||
// 置空工具类引用,帮助GC回收
|
||||
mAppConfigUtils = null;
|
||||
@@ -142,29 +158,23 @@ public class AssistantService extends Service {
|
||||
|
||||
// 绑定主服务,监听连接状态,添加结果日志
|
||||
Intent bindIntent = new Intent(AssistantService.this, ControlCenterService.class);
|
||||
boolean bindResult = bindService(bindIntent, mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
boolean bindResult = bindService(bindIntent, mMyServiceConnection, BIND_FLAG);
|
||||
LogUtils.d(TAG, "wakeupAndBindMain: 绑定主服务结果=" + bindResult + " | 绑定标记=BIND_IMPORTANT");
|
||||
}
|
||||
|
||||
// ================================== 内部类(服务连接状态监听)=================================
|
||||
// ================================== 辅助工具方法(拆分独立逻辑,提高可维护性)=================================
|
||||
/**
|
||||
* 服务连接状态监听器
|
||||
* 主服务连接成功时记录状态,断开时自动重连
|
||||
* 解绑主服务,包含异常捕获与状态日志
|
||||
*/
|
||||
private class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
LogUtils.d(TAG, "onServiceConnected: 主服务连接成功 | 组件名=" + name.getClassName() + " | Binder=" + service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected: 主服务连接断开 | 组件名=" + name.getClassName());
|
||||
// 主服务断开且配置启用时,重新唤醒绑定
|
||||
if (mAppConfigUtils != null && mAppConfigUtils.isServiceEnabled()) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected: 尝试重新唤醒并绑定主服务");
|
||||
wakeupAndBindMain();
|
||||
private void unbindMainService() {
|
||||
if (mMyServiceConnection != null) {
|
||||
try {
|
||||
unbindService(mMyServiceConnection);
|
||||
LogUtils.d(TAG, "unbindMainService: 已成功解绑ControlCenterService");
|
||||
} catch (IllegalArgumentException e) {
|
||||
LogUtils.w(TAG, "unbindMainService: 解绑服务失败,服务未绑定 | " + e.getMessage());
|
||||
}
|
||||
mMyServiceConnection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,68 +28,65 @@ import java.util.List;
|
||||
public class ControlCenterService extends Service {
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
public static final String TAG = "ControlCenterService";
|
||||
|
||||
// 超时/阈值常量
|
||||
private static final long THREAD_STOP_TIMEOUT = 1000L;
|
||||
// 服务返回策略常量
|
||||
private static final int SERVICE_RETURN_STICKY = START_STICKY;
|
||||
private static final int DEFAULT_CHARGE_REMINDER_VALUE = 80;
|
||||
private static final int DEFAULT_USAGE_REMINDER_VALUE = 20;
|
||||
private static final int DEFAULT_BATTERY_DETECT_INTERVAL = 1000;
|
||||
private static final int RUNNING_SERVICE_LIST_LIMIT = 100;
|
||||
|
||||
// ================================== 成员变量区(按功能分层,volatile保证多线程可见性)=================================
|
||||
// 服务控制配置
|
||||
private ControlCenterServiceBean mServiceControlBean;
|
||||
// 业务核心组件
|
||||
private ControlCenterServiceHandler mServiceHandler;
|
||||
private ControlCenterServiceReceiver mControlCenterServiceReceiver;
|
||||
private NotificationManagerUtils mNotificationManager;
|
||||
private AppConfigBean mCurrentConfigBean;
|
||||
private NotificationMessage mForegroundNotifyMsg;
|
||||
// 服务状态标记(volatile保证多线程可见性)
|
||||
// ================================== 静态状态标记(volatile保证多线程可见性)=================================
|
||||
private static volatile boolean isServiceRunning = false;
|
||||
private static volatile boolean mIsDestroyed = true;
|
||||
|
||||
// ================================== 服务生命周期方法(按执行顺序排列:onCreate→onStartCommand→onBind→onDestroy)=================================
|
||||
// ================================== 成员变量区(按功能分层:配置→核心组件→通知相关)=================================
|
||||
// 服务控制配置
|
||||
private ControlCenterServiceBean mServiceControlBean;
|
||||
private AppConfigBean mCurrentConfigBean;
|
||||
// 业务核心组件
|
||||
private ControlCenterServiceHandler mServiceHandler;
|
||||
private ControlCenterServiceReceiver mControlCenterServiceReceiver;
|
||||
// 通知相关
|
||||
private NotificationManagerUtils mNotificationManager;
|
||||
private NotificationMessage mForegroundNotifyMsg;
|
||||
|
||||
// ================================== 服务生命周期方法(按执行顺序:onCreate→onStartCommand→onBind→onDestroy)=================================
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, "onCreate: 服务启动 | 线程=" + Thread.currentThread().getName() + " | 进程ID=" + android.os.Process.myPid());
|
||||
LogUtils.d(TAG, "onCreate执行 | 线程=" + Thread.currentThread().getName() + " | 进程ID=" + android.os.Process.myPid());
|
||||
runCoreServiceLogic();
|
||||
LogUtils.d(TAG, "onCreate: 服务初始化完成 | 前台状态=" + isServiceRunning + " | 服务启用=" + (mServiceControlBean != null && mServiceControlBean.isEnableService()));
|
||||
LogUtils.d(TAG, "onCreate完成 | 前台状态=" + isServiceRunning + " | 服务启用=" + (mServiceControlBean != null && mServiceControlBean.isEnableService()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "onStartCommand: 触发 | intent=" + intent + " | flags=" + flags + " | startId=" + startId);
|
||||
LogUtils.d(TAG, "onStartCommand: action=" + (intent != null ? intent.getAction() : "null"));
|
||||
|
||||
LogUtils.d(TAG, "onStartCommand执行 | startId=" + startId + " | action=" + (intent != null ? intent.getAction() : "null"));
|
||||
loadLatestServiceControlConfig();
|
||||
runCoreServiceLogic();
|
||||
|
||||
int returnFlag = (mServiceControlBean != null && mServiceControlBean.isEnableService())
|
||||
? SERVICE_RETURN_STICKY
|
||||
: super.onStartCommand(intent, flags, startId);
|
||||
|
||||
LogUtils.d(TAG, "onStartCommand: 处理完成 | 返回策略=" + (returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
|
||||
LogUtils.d(TAG, "onStartCommand完成 | 返回策略=" + (returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
|
||||
return returnFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
LogUtils.d(TAG, "onBind: 绑定请求 | intent=" + intent);
|
||||
LogUtils.d(TAG, "onBind执行 | intent=" + intent);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
LogUtils.d(TAG, "onDestroy: 服务销毁流程启动");
|
||||
LogUtils.d(TAG, "onDestroy执行:服务销毁流程启动");
|
||||
super.onDestroy();
|
||||
|
||||
// 资源释放顺序:前台服务 → 线程 → 广播接收器 → Handler → 通知 → 引用(避免内存泄漏)
|
||||
stopForegroundService();
|
||||
RemindThread.stopRemindThreadSafely();
|
||||
if (mControlCenterServiceReceiver != null) {
|
||||
mControlCenterServiceReceiver.release();
|
||||
LogUtils.d(TAG, "onDestroy: 广播接收器已释放");
|
||||
}
|
||||
releaseBroadcastReceiver();
|
||||
destroyHandler();
|
||||
releaseNotificationResource();
|
||||
clearAllReferences();
|
||||
@@ -101,7 +98,7 @@ public class ControlCenterService extends Service {
|
||||
isServiceRunning = false;
|
||||
mIsDestroyed = true;
|
||||
|
||||
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
|
||||
LogUtils.d(TAG, "onDestroy完成:服务销毁完成");
|
||||
}
|
||||
|
||||
// ================================== 核心业务逻辑(独立抽取,统一调用)=================================
|
||||
@@ -110,11 +107,11 @@ public class ControlCenterService extends Service {
|
||||
* 避免重复初始化,保证前台服务优先启动
|
||||
*/
|
||||
private synchronized void runCoreServiceLogic() {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 执行核心逻辑");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic执行");
|
||||
loadLatestServiceControlConfig();
|
||||
|
||||
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 服务启用=" + serviceEnabled + " | 已运行=" + isServiceRunning + " | 已销毁=" + mIsDestroyed);
|
||||
LogUtils.d(TAG, "runCoreServiceLogic:服务启用=" + serviceEnabled + " | 已运行=" + isServiceRunning + " | 已销毁=" + mIsDestroyed);
|
||||
|
||||
if (serviceEnabled && !isServiceRunning) {
|
||||
isServiceRunning = true;
|
||||
@@ -123,14 +120,14 @@ public class ControlCenterService extends Service {
|
||||
if (initForegroundNotificationImmediately()) {
|
||||
loadDefaultConfig();
|
||||
initServiceBusinessLogic();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心组件初始化成功");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic:核心组件初始化成功");
|
||||
} else {
|
||||
LogUtils.e(TAG, "runCoreServiceLogic: 前台通知初始化失败,终止业务");
|
||||
LogUtils.e(TAG, "runCoreServiceLogic:前台通知初始化失败,终止业务");
|
||||
stopForegroundService();
|
||||
isServiceRunning = false;
|
||||
}
|
||||
} else {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 无需执行核心逻辑");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic:无需执行核心逻辑");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,11 +137,11 @@ public class ControlCenterService extends Service {
|
||||
* @return true=成功 false=失败
|
||||
*/
|
||||
private boolean initForegroundNotificationImmediately() {
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately执行");
|
||||
try {
|
||||
if (mNotificationManager == null) {
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 通知工具类初始化完成");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately:通知工具类初始化完成");
|
||||
}
|
||||
|
||||
if (mForegroundNotifyMsg == null) {
|
||||
@@ -152,15 +149,15 @@ public class ControlCenterService extends Service {
|
||||
mForegroundNotifyMsg.setTitle("电池监测服务");
|
||||
mForegroundNotifyMsg.setContent("后台运行中");
|
||||
mForegroundNotifyMsg.setRemindMSG("service_running");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 通知消息构建完成");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately:通知消息构建完成");
|
||||
}
|
||||
|
||||
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
|
||||
ToastUtils.show("电池监测服务已启动");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功 | ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately:前台通知发送成功 | ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "initForegroundNotificationImmediately: 通知初始化异常", e);
|
||||
LogUtils.e(TAG, "initForegroundNotificationImmediately:通知初始化异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -169,12 +166,12 @@ public class ControlCenterService extends Service {
|
||||
* 停止前台服务并取消通知
|
||||
*/
|
||||
private void stopForegroundService() {
|
||||
LogUtils.d(TAG, "stopForegroundService: 停止前台服务");
|
||||
LogUtils.d(TAG, "stopForegroundService执行");
|
||||
try {
|
||||
stopForeground(true);
|
||||
LogUtils.d(TAG, "stopForegroundService: 前台服务已停止,通知已取消");
|
||||
LogUtils.d(TAG, "stopForegroundService:前台服务已停止,通知已取消");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "stopForegroundService: 停止异常", e);
|
||||
LogUtils.e(TAG, "stopForegroundService:停止异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,13 +180,13 @@ public class ControlCenterService extends Service {
|
||||
* 加载本地最新服务控制配置
|
||||
*/
|
||||
private void loadLatestServiceControlConfig() {
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取服务配置");
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig执行");
|
||||
ControlCenterServiceBean latestBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
|
||||
if (latestBean != null) {
|
||||
mServiceControlBean = latestBean;
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig: 配置读取成功 | 启用=" + mServiceControlBean.isEnableService());
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig:配置读取成功 | 启用=" + mServiceControlBean.isEnableService());
|
||||
} else {
|
||||
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无配置,沿用内存配置");
|
||||
LogUtils.w(TAG, "loadLatestServiceControlConfig:本地无配置,沿用内存配置");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,40 +194,54 @@ public class ControlCenterService extends Service {
|
||||
* 加载默认业务配置(首次启动兜底)
|
||||
*/
|
||||
private void loadDefaultConfig() {
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置");
|
||||
LogUtils.d(TAG, "loadDefaultConfig执行");
|
||||
if (mCurrentConfigBean == null) {
|
||||
mCurrentConfigBean = new AppConfigBean();
|
||||
mCurrentConfigBean.setEnableChargeReminder(true);
|
||||
mCurrentConfigBean.setChargeReminderValue(80);
|
||||
mCurrentConfigBean.setChargeReminderValue(DEFAULT_CHARGE_REMINDER_VALUE);
|
||||
mCurrentConfigBean.setEnableUsageReminder(true);
|
||||
mCurrentConfigBean.setUsageReminderValue(20);
|
||||
mCurrentConfigBean.setBatteryDetectInterval(1000);
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成 | 充电阈值=80 | 耗电阈值=20 | 检测间隔=1000ms");
|
||||
mCurrentConfigBean.setUsageReminderValue(DEFAULT_USAGE_REMINDER_VALUE);
|
||||
mCurrentConfigBean.setBatteryDetectInterval(DEFAULT_BATTERY_DETECT_INTERVAL);
|
||||
LogUtils.d(TAG, "loadDefaultConfig:默认配置加载完成 | 充电阈值=" + DEFAULT_CHARGE_REMINDER_VALUE + " | 耗电阈值=" + DEFAULT_USAGE_REMINDER_VALUE + " | 检测间隔=" + DEFAULT_BATTERY_DETECT_INTERVAL + "ms");
|
||||
} else {
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 内存已有配置,无需加载");
|
||||
LogUtils.d(TAG, "loadDefaultConfig:内存已有配置,无需加载");
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 业务组件初始化与销毁(Handler/线程等)=================================
|
||||
// ================================== 业务组件初始化与销毁(Handler/广播/线程等)=================================
|
||||
/**
|
||||
* 初始化Handler等核心业务组件
|
||||
*/
|
||||
private void initServiceBusinessLogic() {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 初始化业务组件");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic执行");
|
||||
// 初始化Handler
|
||||
if (mServiceHandler == null) {
|
||||
mServiceHandler = new ControlCenterServiceHandler(this);
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: Handler初始化完成");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:Handler初始化完成");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: Handler已存在");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:Handler已存在");
|
||||
}
|
||||
// 初始化广播接收器
|
||||
if (mControlCenterServiceReceiver == null) {
|
||||
mControlCenterServiceReceiver = new ControlCenterServiceReceiver(this);
|
||||
mControlCenterServiceReceiver.registerAction(this);
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 广播接收器初始化并注册完成");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:广播接收器初始化并注册完成 | 接收器=" + mControlCenterServiceReceiver);
|
||||
} else {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 广播接收器已存在");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:广播接收器已存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放广播接收器资源
|
||||
*/
|
||||
private void releaseBroadcastReceiver() {
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver执行");
|
||||
if (mControlCenterServiceReceiver != null) {
|
||||
mControlCenterServiceReceiver.release();
|
||||
mControlCenterServiceReceiver = null;
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver:广播接收器已释放");
|
||||
} else {
|
||||
LogUtils.w(TAG, "releaseBroadcastReceiver:广播接收器实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,13 +249,13 @@ public class ControlCenterService extends Service {
|
||||
* 销毁Handler,移除所有消息和回调,防止内存泄漏
|
||||
*/
|
||||
private void destroyHandler() {
|
||||
LogUtils.d(TAG, "destroyHandler: 销毁Handler");
|
||||
LogUtils.d(TAG, "destroyHandler执行");
|
||||
if (mServiceHandler != null) {
|
||||
mServiceHandler.removeCallbacksAndMessages(null);
|
||||
mServiceHandler = null;
|
||||
LogUtils.d(TAG, "destroyHandler: Handler已销毁");
|
||||
LogUtils.d(TAG, "destroyHandler:Handler已销毁");
|
||||
} else {
|
||||
LogUtils.w(TAG, "destroyHandler: Handler实例为空");
|
||||
LogUtils.w(TAG, "destroyHandler:Handler实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,13 +263,13 @@ public class ControlCenterService extends Service {
|
||||
* 释放通知工具类资源
|
||||
*/
|
||||
private void releaseNotificationResource() {
|
||||
LogUtils.d(TAG, "releaseNotificationResource: 释放通知资源");
|
||||
LogUtils.d(TAG, "releaseNotificationResource执行");
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.release();
|
||||
mNotificationManager = null;
|
||||
LogUtils.d(TAG, "releaseNotificationResource: 通知资源已释放");
|
||||
LogUtils.d(TAG, "releaseNotificationResource:通知资源已释放");
|
||||
} else {
|
||||
LogUtils.w(TAG, "releaseNotificationResource: 通知工具类实例为空");
|
||||
LogUtils.w(TAG, "releaseNotificationResource:通知工具类实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +277,10 @@ public class ControlCenterService extends Service {
|
||||
* 置空所有引用,防止内存泄漏
|
||||
*/
|
||||
private void clearAllReferences() {
|
||||
LogUtils.d(TAG, "clearAllReferences: 清理内存引用");
|
||||
LogUtils.d(TAG, "clearAllReferences执行");
|
||||
mForegroundNotifyMsg = null;
|
||||
mServiceControlBean = null;
|
||||
LogUtils.d(TAG, "clearAllReferences: 引用清理完成");
|
||||
LogUtils.d(TAG, "clearAllReferences:引用清理完成");
|
||||
}
|
||||
|
||||
// ================================== 外部调用接口(静态方法,提供服务启停/配置更新入口)=================================
|
||||
@@ -278,25 +289,25 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void startControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, "startControlCenterService: 外部启动服务 | context=" + context);
|
||||
LogUtils.d(TAG, "startControlCenterService执行 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "startControlCenterService: Context为空,启动失败");
|
||||
LogUtils.e(TAG, "startControlCenterService:Context为空,启动失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存启用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(true);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "startControlCenterService: 服务启用配置已保存");
|
||||
LogUtils.d(TAG, "startControlCenterService:服务启用配置已保存 | 配置=" + controlBean);
|
||||
|
||||
// 启动服务(区分API版本)
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService: 以前台服务方式启动(API26+)");
|
||||
LogUtils.d(TAG, "startControlCenterService:以前台服务方式启动(API26+)");
|
||||
} else {
|
||||
context.startService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService: 以普通服务方式启动(API26-)");
|
||||
LogUtils.d(TAG, "startControlCenterService:以普通服务方式启动(API26-)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,39 +316,39 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void stopControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, "stopControlCenterService: 外部停止服务 | context=" + context);
|
||||
LogUtils.d(TAG, "stopControlCenterService执行 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "stopControlCenterService: Context为空,停止失败");
|
||||
LogUtils.e(TAG, "stopControlCenterService:Context为空,停止失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存停用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "stopControlCenterService: 服务停用配置已保存");
|
||||
LogUtils.d(TAG, "stopControlCenterService:服务停用配置已保存 | 配置=" + controlBean);
|
||||
|
||||
// 停止服务
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
context.stopService(intent);
|
||||
LogUtils.d(TAG, "stopControlCenterService: 停止指令已发送");
|
||||
LogUtils.d(TAG, "stopControlCenterService:停止指令已发送");
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部更新配置并触发线程重启
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void updateStatus(Context context) {
|
||||
LogUtils.d(TAG, "updateStatus: 外部更新配置 | context=" + context);
|
||||
public static void sendAppConfigStatusUpdateMessage(Context context) {
|
||||
LogUtils.d(TAG, "sendAppConfigStatusUpdateMessage执行 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "updateStatus: 参数为空,更新失败");
|
||||
LogUtils.e(TAG, "sendAppConfigStatusUpdateMessage:参数为空,更新失败");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
Intent intent = new Intent(context, ControlCenterServiceReceiver.class);
|
||||
intent.setAction(ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.sendBroadcast(intent);
|
||||
LogUtils.d(TAG, "updateStatus: 配置更新广播已发送 | action=" + ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
|
||||
LogUtils.d(TAG, "sendAppConfigStatusUpdateMessage:配置更新广播已发送 | action=" + ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,28 +356,28 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void checkIgnoreBatteryOptimization(Context context) {
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 检查电池优化 | context=" + context);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization执行 | context=" + context);
|
||||
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization: 无需检查(Context为空或API<23)");
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization:无需检查(Context为空或API<23)");
|
||||
return;
|
||||
}
|
||||
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (powerManager == null) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: PowerManager获取失败");
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization:PowerManager获取失败");
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = context.getPackageName();
|
||||
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已忽略电池优化=" + isIgnored);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization:已忽略电池优化=" + isIgnored);
|
||||
|
||||
if (!isIgnored) {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
context.startActivity(intent);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已跳转至系统设置页 | package=" + packageName);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization:已跳转至系统设置页 | package=" + packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,15 +388,15 @@ public class ControlCenterService extends Service {
|
||||
* @return true=运行中 false=未运行
|
||||
*/
|
||||
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, "isServiceRunning: 检查服务状态 | context=" + context + " | service=" + (serviceClass != null ? serviceClass.getName() : "null"));
|
||||
LogUtils.d(TAG, "isServiceRunning执行 | context=" + context + " | service=" + (serviceClass != null ? serviceClass.getName() : "null"));
|
||||
if (context == null || serviceClass == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning: 参数为空");
|
||||
LogUtils.e(TAG, "isServiceRunning:参数为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (am == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败");
|
||||
LogUtils.e(TAG, "isServiceRunning:ActivityManager获取失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -406,10 +417,10 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceRunning: API30+ 判断结果=" + isRunning);
|
||||
LogUtils.d(TAG, "isServiceRunning:API30+ 判断结果=" + isRunning);
|
||||
} else {
|
||||
// API30- 通过服务列表判断
|
||||
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(100);
|
||||
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(RUNNING_SERVICE_LIST_LIMIT);
|
||||
if (services != null) {
|
||||
for (ActivityManager.RunningServiceInfo info : services) {
|
||||
if (serviceClassName.equals(info.service.getClassName())) {
|
||||
@@ -418,13 +429,13 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceRunning: API30- 判断结果=" + isRunning);
|
||||
LogUtils.d(TAG, "isServiceRunning:API30- 判断结果=" + isRunning);
|
||||
}
|
||||
|
||||
// 兜底判断:配置启用状态
|
||||
if (!isRunning) {
|
||||
isRunning = isServiceStarted(context, serviceClass);
|
||||
LogUtils.d(TAG, "isServiceRunning: 兜底判断结果=" + isRunning);
|
||||
LogUtils.d(TAG, "isServiceRunning:兜底判断结果=" + isRunning);
|
||||
}
|
||||
return isRunning;
|
||||
}
|
||||
@@ -433,29 +444,44 @@ public class ControlCenterService extends Service {
|
||||
* 兜底判断服务是否已启动(通过配置文件)
|
||||
*/
|
||||
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, "isServiceStarted: 兜底判断服务状态");
|
||||
LogUtils.d(TAG, "isServiceStarted执行");
|
||||
try {
|
||||
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
|
||||
return controlBean != null && controlBean.isEnableService();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "isServiceStarted: 兜底判断异常", e);
|
||||
LogUtils.e(TAG, "isServiceStarted:兜底判断异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 业务方法(配置更新)=================================
|
||||
// ================================== 业务方法(配置更新/电池状态回调)=================================
|
||||
/**
|
||||
* 接收外部配置更新,同步到提醒线程
|
||||
* @param latestConfig 最新配置
|
||||
*/
|
||||
public void notifyAppConfigUpdate(AppConfigBean latestConfig) {
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate: 配置更新 | config=" + latestConfig);
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate执行 | 充电阈值=" + (latestConfig != null ? latestConfig.getChargeReminderValue() : null) + " | 耗电阈值=" + (latestConfig != null ? latestConfig.getUsageReminderValue() : null));
|
||||
if (latestConfig != null && mServiceHandler != null) {
|
||||
mCurrentConfigBean = latestConfig;
|
||||
RemindThread.startRemindThread(this, mServiceHandler, latestConfig);
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate: 配置已同步到提醒线程 | 充电阈值=" + latestConfig.getChargeReminderValue() + " | 耗电阈值=" + latestConfig.getUsageReminderValue());
|
||||
RemindThread.startRemindThreadWithAppConfig(this, mServiceHandler, latestConfig);
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate:配置已同步到提醒线程");
|
||||
} else {
|
||||
LogUtils.e(TAG, "notifyAppConfigUpdate: 参数为空,同步失败 | latestConfig=" + latestConfig + " | mServiceHandler=" + mServiceHandler);
|
||||
LogUtils.e(TAG, "notifyAppConfigUpdate:参数为空,同步失败 | latestConfig=" + latestConfig + " | mServiceHandler=" + mServiceHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收电池状态变化,同步到提醒线程
|
||||
* @param isCharging 是否充电中
|
||||
* @param lastBatteryLevel 最新电池电量
|
||||
*/
|
||||
public void notifyBatteryStateChanged(boolean isCharging, int lastBatteryLevel) {
|
||||
LogUtils.d(TAG, "notifyBatteryStateChanged执行 | 充电中=" + isCharging + " | 电量=" + lastBatteryLevel);
|
||||
if (mServiceHandler != null) {
|
||||
RemindThread.startRemindThreadWithBatteryInfo(this, mServiceHandler, isCharging, lastBatteryLevel);
|
||||
LogUtils.d(TAG, "notifyBatteryStateChanged:电池状态已同步到提醒线程");
|
||||
} else {
|
||||
LogUtils.w(TAG, "notifyBatteryStateChanged:Handler未初始化,同步失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@ import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/19 20:28
|
||||
* @Describe 提醒线程(线程安全单例)
|
||||
* 提醒线程(线程安全单例)
|
||||
* 功能:管理充电/耗电提醒逻辑,触发条件时向Handler发送提醒消息
|
||||
* 适配:Java7 | API30 | 内存泄漏防护 | 多线程状态同步
|
||||
* 对外接口:{@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)}、{@link #stopRemindThreadSafely()}
|
||||
* 对外接口:{@link #startRemindThreadWithAppConfig(Context, ControlCenterServiceHandler, AppConfigBean)}、{@link #startRemindThreadWithBatteryInfo(Context, ControlCenterServiceHandler, boolean, int)}、{@link #stopRemindThreadSafely()}
|
||||
*/
|
||||
public class RemindThread extends Thread {
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
@@ -26,6 +24,12 @@ public class RemindThread extends Thread {
|
||||
|
||||
// 状态常量
|
||||
private static final int INVALID_BATTERY_VALUE = -1;
|
||||
private static final int BATTERY_LEVEL_MIN = 0;
|
||||
private static final int BATTERY_LEVEL_MAX = 100;
|
||||
|
||||
// 提醒类型常量
|
||||
private static final String REMIND_TYPE_CHARGE = "+";
|
||||
private static final String REMIND_TYPE_USAGE = "-";
|
||||
|
||||
// ================================== 单例核心(双重校验锁,保证线程安全)=================================
|
||||
private static volatile RemindThread sInstance;
|
||||
@@ -53,10 +57,11 @@ public class RemindThread extends Thread {
|
||||
|
||||
// ================================== 私有构造器(单例专用,禁止外部实例化)=================================
|
||||
private RemindThread(Context context, ControlCenterServiceHandler handler) {
|
||||
LogUtils.d(TAG, "创建线程实例 | threadId=" + getId() + " | threadName=" + getName());
|
||||
LogUtils.d(TAG, "构造方法执行 | threadId=" + getId() + " | threadName=" + getName());
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
|
||||
resetThreadStateInternal();
|
||||
LogUtils.d(TAG, "构造完成 | 初始状态重置成功");
|
||||
}
|
||||
|
||||
// ================================== 单例获取方法(核心,双重校验锁)=================================
|
||||
@@ -86,11 +91,11 @@ public class RemindThread extends Thread {
|
||||
* @param config 应用配置Bean(非空)
|
||||
* @return true: 启动成功/已在运行;false: 入参非法
|
||||
*/
|
||||
public static boolean startRemindThread(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
|
||||
LogUtils.d(TAG, "请求启动线程 | context=" + context + " | handler=" + handler + " | config=" + config);
|
||||
public static boolean startRemindThreadWithAppConfig(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
|
||||
LogUtils.d(TAG, "startRemindThreadWithAppConfig执行 | context=" + context + " | handler=" + handler + " | config=" + config);
|
||||
// 入参严格校验
|
||||
if (context == null || handler == null || config == null) {
|
||||
LogUtils.e(TAG, "启动失败:入参为空");
|
||||
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler + " | config=" + config);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -111,15 +116,54 @@ public class RemindThread extends Thread {
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.d(TAG, "线程已在运行状态 | threadId=" + instance.getId());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动提醒线程,同步电池信息
|
||||
* @param context 上下文(非空)
|
||||
* @param handler 服务处理器(非空)
|
||||
* @param isCharging 充电状态
|
||||
* @param lastBatteryLevel 最新电量
|
||||
* @return true: 启动成功/已在运行;false: 入参非法
|
||||
*/
|
||||
public static boolean startRemindThreadWithBatteryInfo(Context context, ControlCenterServiceHandler handler, boolean isCharging, int lastBatteryLevel) {
|
||||
LogUtils.d(TAG, "startRemindThreadWithBatteryInfo执行 | context=" + context + " | handler=" + handler + " | isCharging=" + isCharging + " | lastBatteryLevel=" + lastBatteryLevel);
|
||||
// 入参严格校验
|
||||
if (context == null || handler == null) {
|
||||
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler);
|
||||
return false;
|
||||
}
|
||||
|
||||
RemindThread instance = getInstance(context, handler);
|
||||
// 已在提醒状态,仅同步电池信息
|
||||
if (instance.isReminding) {
|
||||
instance.isCharging = isCharging;
|
||||
instance.quantityOfElectricity = lastBatteryLevel;
|
||||
LogUtils.d(TAG, "线程已在运行,同步电池信息 | threadId=" + instance.getId() + " | isCharging=" + isCharging + " | lastBatteryLevel=" + lastBatteryLevel);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 同步电池信息并启动线程
|
||||
instance.isCharging = isCharging;
|
||||
instance.quantityOfElectricity = lastBatteryLevel;
|
||||
if (!instance.isRunning()) {
|
||||
instance.isExist = false;
|
||||
instance.start();
|
||||
LogUtils.d(TAG, "线程启动成功 | threadId=" + instance.getId());
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.d(TAG, "线程已在运行状态 | threadId=" + instance.getId());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全停止线程,优雅销毁单例
|
||||
*/
|
||||
public static void stopRemindThreadSafely() {
|
||||
LogUtils.d(TAG, "请求安全停止线程 | 单例存在=" + (sInstance != null));
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely执行 | 单例存在=" + (sInstance != null));
|
||||
synchronized (RemindThread.class) {
|
||||
if (sInstance == null) {
|
||||
LogUtils.w(TAG, "停止失败:线程实例为空");
|
||||
@@ -176,7 +220,7 @@ public class RemindThread extends Thread {
|
||||
// ================================== 线程核心运行逻辑=================================
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "线程进入运行 | threadId=" + getId() + " | 状态=" + getState());
|
||||
LogUtils.d(TAG, "run执行 | threadId=" + getId() + " | 状态=" + getState());
|
||||
|
||||
// 初始化提醒状态(加锁保护,避免多线程竞争)
|
||||
synchronized (mLock) {
|
||||
@@ -198,18 +242,19 @@ public class RemindThread extends Thread {
|
||||
if (isExist) break;
|
||||
|
||||
// 电量有效性校验(非0-100视为无效)
|
||||
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
||||
LogUtils.w(TAG, "电量无效,退出循环 | 当前电量=" + quantityOfElectricity);
|
||||
break;
|
||||
if (quantityOfElectricity < BATTERY_LEVEL_MIN || quantityOfElectricity > BATTERY_LEVEL_MAX) {
|
||||
LogUtils.w(TAG, "电量无效,跳过本次检测 | 当前电量=" + quantityOfElectricity);
|
||||
safeSleepInternal(sleepTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 充电提醒触发逻辑
|
||||
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
|
||||
LogUtils.d(TAG, "触发充电提醒 | 当前电量=" + quantityOfElectricity + " ≥ 阈值=" + chargeReminderValue);
|
||||
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
|
||||
sendNotificationMessageInternal(REMIND_TYPE_CHARGE, quantityOfElectricity, isCharging);
|
||||
} else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
|
||||
LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + " ≤ 阈值=" + usageReminderValue);
|
||||
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
|
||||
sendNotificationMessageInternal(REMIND_TYPE_USAGE, quantityOfElectricity, isCharging);
|
||||
}
|
||||
|
||||
// 安全休眠,保留中断标记
|
||||
@@ -222,7 +267,7 @@ public class RemindThread extends Thread {
|
||||
|
||||
// 循环退出,清理状态
|
||||
cleanThreadStateInternal();
|
||||
LogUtils.d(TAG, "线程运行结束 | threadId=" + getId());
|
||||
LogUtils.d(TAG, "run结束 | threadId=" + getId());
|
||||
}
|
||||
|
||||
// ================================== 内部业务辅助方法=================================
|
||||
@@ -233,6 +278,7 @@ public class RemindThread extends Thread {
|
||||
* @param isCharging 充电状态
|
||||
*/
|
||||
private void sendNotificationMessageInternal(String type, int battery, boolean isCharging) {
|
||||
LogUtils.d(TAG, "sendNotificationMessageInternal执行 | 类型=" + type + " | 电量=" + battery + " | isCharging=" + isCharging);
|
||||
// 前置状态校验
|
||||
if (isExist || !isReminding) {
|
||||
LogUtils.d(TAG, "消息发送跳过:线程已退出或提醒关闭");
|
||||
@@ -280,7 +326,7 @@ public class RemindThread extends Thread {
|
||||
* 重置线程初始状态(构造器专用)
|
||||
*/
|
||||
private void resetThreadStateInternal() {
|
||||
LogUtils.d(TAG, "重置线程初始状态");
|
||||
LogUtils.d(TAG, "resetThreadStateInternal执行");
|
||||
// 状态标记初始化
|
||||
isExist = false;
|
||||
isReminding = false;
|
||||
@@ -298,7 +344,7 @@ public class RemindThread extends Thread {
|
||||
* 清理线程运行状态(循环退出时调用)
|
||||
*/
|
||||
private void cleanThreadStateInternal() {
|
||||
LogUtils.d(TAG, "清理线程运行状态");
|
||||
LogUtils.d(TAG, "cleanThreadStateInternal执行");
|
||||
isReminding = false;
|
||||
isExist = true;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
@@ -313,7 +359,7 @@ public class RemindThread extends Thread {
|
||||
* @param config 应用配置Bean
|
||||
*/
|
||||
public void setAppConfigBean(AppConfigBean config) {
|
||||
LogUtils.d(TAG, "同步应用配置 | config=" + config);
|
||||
LogUtils.d(TAG, "setAppConfigBean执行 | config=" + config);
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, "配置同步失败:配置Bean为空");
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
@@ -323,22 +369,22 @@ public class RemindThread extends Thread {
|
||||
// 配置参数同步 + 范围校验(确保参数合法)
|
||||
isEnableChargeReminder = config.isEnableChargeReminder();
|
||||
isEnableUsageReminder = config.isEnableUsageReminder();
|
||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
|
||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
|
||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
||||
quantityOfElectricity = (config.getCurrentBatteryValue() >= 0 && config.getCurrentBatteryValue() <= 100)
|
||||
quantityOfElectricity = (config.getCurrentBatteryValue() >= BATTERY_LEVEL_MIN && config.getCurrentBatteryValue() <= BATTERY_LEVEL_MAX)
|
||||
? config.getCurrentBatteryValue() : INVALID_BATTERY_VALUE;
|
||||
isCharging = config.isCharging();
|
||||
isReminding = isEnableChargeReminder || isEnableUsageReminder;
|
||||
|
||||
LogUtils.d(TAG, "配置同步完成 | 休眠时间=" + sleepTime + "ms | 提醒开启=" + isReminding + " | 当前电量=" + quantityOfElectricity);
|
||||
LogUtils.d(TAG, "配置同步完成 | 休眠时间=" + sleepTime + "ms | 提醒开启=" + isReminding + " | 当前电量=" + quantityOfElectricity + " | 充电阈值=" + chargeReminderValue + " | 耗电阈值=" + usageReminderValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放线程内部资源,杜绝内存泄漏
|
||||
*/
|
||||
private void releaseResourcesInternal() {
|
||||
LogUtils.d(TAG, "释放线程内部资源");
|
||||
LogUtils.d(TAG, "releaseResourcesInternal执行");
|
||||
// 释放上下文引用
|
||||
mContext = null;
|
||||
// 清空WeakReference
|
||||
@@ -356,13 +402,13 @@ public class RemindThread extends Thread {
|
||||
*/
|
||||
private boolean isRunning() {
|
||||
boolean running = !isExist && isAlive();
|
||||
LogUtils.d(TAG, "线程运行状态判断 | 运行中=" + running + " | 退出标记=" + isExist + " | 存活=" + isAlive());
|
||||
LogUtils.d(TAG, "isRunning执行 | 运行中=" + running + " | 退出标记=" + isExist + " | 存活=" + isAlive());
|
||||
return running;
|
||||
}
|
||||
|
||||
// ================================== Getter/Setter(按需开放)=================================
|
||||
public void setIsExist(boolean isExist) {
|
||||
LogUtils.d(TAG, "设置线程退出标记 | isExist=" + isExist);
|
||||
LogUtils.d(TAG, "setIsExist执行 | isExist=" + isExist);
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/17 13:42
|
||||
* @Describe 通知工具类:统一管理前台服务/电池提醒通知,适配API19-30,Java7兼容,前台服务无铃声,提醒通知用系统默认铃声
|
||||
* 通知工具类:统一管理前台服务/电池提醒通知
|
||||
* 适配:API19-30 | Java7 | 小米手机
|
||||
* 特性:前台服务无铃声、提醒通知系统默认铃声、API分级适配、内存泄漏防护
|
||||
*/
|
||||
public class NotificationManagerUtils {
|
||||
// ================================== 静态常量(置顶统一管理,杜绝魔法值)=================================
|
||||
@@ -35,6 +35,14 @@ public class NotificationManagerUtils {
|
||||
public static final int NOTIFY_ID_REMIND = 1002;
|
||||
// 低版本兼容:默认通知图标(API<21 避免显示异常)
|
||||
private static final int NOTIFICATION_DEFAULT_ICON = R.drawable.ic_launcher;
|
||||
// 通知内容兜底常量
|
||||
private static final String FOREGROUND_NOTIFY_TITLE_DEFAULT = "电池服务运行中";
|
||||
private static final String FOREGROUND_NOTIFY_CONTENT_DEFAULT = "后台监测电池状态";
|
||||
private static final String REMIND_NOTIFY_TITLE_DEFAULT = "电池状态提醒";
|
||||
private static final String REMIND_NOTIFY_CONTENT_DEFAULT = "电池状态异常,请及时处理";
|
||||
// PendingIntent请求码
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_FOREGROUND = 0;
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_REMIND = 1;
|
||||
|
||||
// ================================== 成员变量(私有封装,按依赖优先级排序)=================================
|
||||
// 核心上下文(应用级,避免内存泄漏)
|
||||
@@ -46,10 +54,10 @@ public class NotificationManagerUtils {
|
||||
|
||||
// ================================== 构造方法(初始化核心资源,前置校验)=================================
|
||||
public NotificationManagerUtils(Context context) {
|
||||
LogUtils.d(TAG, "NotificationManagerUtils init start");
|
||||
LogUtils.d(TAG, "构造方法执行");
|
||||
// 前置校验:Context非空
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "init failed: context is null");
|
||||
LogUtils.e(TAG, "构造失败:context is null");
|
||||
return;
|
||||
}
|
||||
// 初始化核心资源
|
||||
@@ -57,7 +65,7 @@ public class NotificationManagerUtils {
|
||||
this.mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
// 初始化通知渠道(API26+ 必需)
|
||||
initNotificationChannels();
|
||||
LogUtils.d(TAG, "NotificationManagerUtils init success");
|
||||
LogUtils.d(TAG, "构造完成:核心资源初始化成功");
|
||||
}
|
||||
|
||||
// ================================== 核心初始化方法(通知渠道,API分级适配)=================================
|
||||
@@ -67,12 +75,12 @@ public class NotificationManagerUtils {
|
||||
private void initNotificationChannels() {
|
||||
// API<26 无渠道机制,直接返回
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
LogUtils.d(TAG, "initNotificationChannels: API<26, no need channel");
|
||||
LogUtils.d(TAG, "initNotificationChannels:API<26,无需创建渠道");
|
||||
return;
|
||||
}
|
||||
// 通知服务为空,避免空指针
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "initNotificationChannels failed: NotificationManager is null");
|
||||
LogUtils.e(TAG, "initNotificationChannels失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,14 +106,14 @@ public class NotificationManagerUtils {
|
||||
remindChannel.setDescription("电池满电/低电量提醒,系统默认铃声,无振动");
|
||||
remindChannel.enableLights(true);
|
||||
remindChannel.enableVibration(false);
|
||||
remindChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
remindChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
remindChannel.setShowBadge(false);
|
||||
remindChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
|
||||
// 注册渠道到系统
|
||||
mNotificationManager.createNotificationChannel(foregroundChannel);
|
||||
mNotificationManager.createNotificationChannel(remindChannel);
|
||||
LogUtils.d(TAG, "initNotificationChannels success: foreground+remind channel created");
|
||||
LogUtils.d(TAG, "initNotificationChannels成功:创建前台服务+电池提醒渠道");
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(前台服务通知:启动/更新/取消)=================================
|
||||
@@ -113,26 +121,26 @@ public class NotificationManagerUtils {
|
||||
* 启动前台服务通知(API30适配,无铃声)
|
||||
*/
|
||||
public void startForegroundServiceNotify(Service service, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify start, notifyId: " + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
// 前置校验:参数非空
|
||||
if (service == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify failed: param is null");
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify失败:param is null | service=" + service + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建前台通知
|
||||
mForegroundServiceNotify = buildForegroundNotification(message);
|
||||
if (mForegroundServiceNotify == null) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify failed: build notify null");
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动前台服务(API30无FOREGROUND_SERVICE_TYPE限制,全版本通用)
|
||||
try {
|
||||
service.startForeground(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify success");
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify exception", e);
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,23 +148,23 @@ public class NotificationManagerUtils {
|
||||
* 更新前台服务通知内容(复用通知ID,保持无铃声)
|
||||
*/
|
||||
public void updateForegroundServiceNotify(NotificationMessage message) {
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify start, notifyId: " + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
if (message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify failed: param is null");
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify失败:param is null | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
mForegroundServiceNotify = buildForegroundNotification(message);
|
||||
if (mForegroundServiceNotify == null) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify failed: build notify null");
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify success");
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify exception", e);
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,10 +172,10 @@ public class NotificationManagerUtils {
|
||||
* 取消前台服务通知(Service销毁时调用)
|
||||
*/
|
||||
public void cancelForegroundServiceNotify() {
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify start, notifyId: " + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
cancelNotification(NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
mForegroundServiceNotify = null; // 置空释放
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify success");
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify成功");
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(电池提醒通知:发送)=================================
|
||||
@@ -175,23 +183,23 @@ public class NotificationManagerUtils {
|
||||
* 发送电池提醒通知(系统默认铃声,无振动)
|
||||
*/
|
||||
public void showRemindNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "showRemindNotification start, notifyId: " + NOTIFY_ID_REMIND);
|
||||
LogUtils.d(TAG, "showRemindNotification执行 | notifyId=" + NOTIFY_ID_REMIND);
|
||||
if (context == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "showRemindNotification failed: param is null");
|
||||
LogUtils.e(TAG, "showRemindNotification失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification remindNotify = buildRemindNotification(context, message);
|
||||
if (remindNotify == null) {
|
||||
LogUtils.e(TAG, "showRemindNotification failed: build notify null");
|
||||
LogUtils.e(TAG, "showRemindNotification失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_REMIND, remindNotify);
|
||||
LogUtils.d(TAG, "showRemindNotification success");
|
||||
LogUtils.d(TAG, "showRemindNotification成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "showRemindNotification exception", e);
|
||||
LogUtils.e(TAG, "showRemindNotification异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,15 +208,16 @@ public class NotificationManagerUtils {
|
||||
* 取消指定ID的通知
|
||||
*/
|
||||
public void cancelNotification(int notifyId) {
|
||||
LogUtils.d(TAG, "cancelNotification执行 | notifyId=" + notifyId);
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "cancelNotification failed: NotificationManager is null");
|
||||
LogUtils.e(TAG, "cancelNotification失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mNotificationManager.cancel(notifyId);
|
||||
LogUtils.d(TAG, "cancelNotification success, notifyId: " + notifyId);
|
||||
LogUtils.d(TAG, "cancelNotification成功 | notifyId=" + notifyId);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "cancelNotification exception, notifyId: " + notifyId, e);
|
||||
LogUtils.e(TAG, "cancelNotification异常 | notifyId=" + notifyId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,15 +225,16 @@ public class NotificationManagerUtils {
|
||||
* 取消所有通知(兜底场景使用)
|
||||
*/
|
||||
public void cancelAllNotifications() {
|
||||
LogUtils.d(TAG, "cancelAllNotifications执行");
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "cancelAllNotifications failed: NotificationManager is null");
|
||||
LogUtils.e(TAG, "cancelAllNotifications失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mNotificationManager.cancelAll();
|
||||
LogUtils.d(TAG, "cancelAllNotifications success");
|
||||
LogUtils.d(TAG, "cancelAllNotifications成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "cancelAllNotifications exception", e);
|
||||
LogUtils.e(TAG, "cancelAllNotifications异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,14 +243,16 @@ public class NotificationManagerUtils {
|
||||
* 构建前台服务通知(全版本无铃声+无振动)
|
||||
*/
|
||||
private Notification buildForegroundNotification(NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildForegroundNotification执行");
|
||||
if (message == null || mContext == null) {
|
||||
LogUtils.e(TAG, "buildForegroundNotification failed: param is null");
|
||||
LogUtils.e(TAG, "buildForegroundNotification失败:param is null | message=" + message + " | mContext=" + mContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : "电池服务运行中";
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : "后台监测电池状态";
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : FOREGROUND_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : FOREGROUND_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildForegroundNotification:title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
@@ -262,7 +274,7 @@ public class NotificationManagerUtils {
|
||||
.setAutoCancel(false)
|
||||
.setOngoing(true) // 不可手动关闭
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(createJumpPendingIntent(mContext, 0));
|
||||
.setContentIntent(createJumpPendingIntent(mContext, PENDING_INTENT_REQUEST_CODE_FOREGROUND));
|
||||
|
||||
// API21+ 新增大图标+主题色
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
@@ -279,14 +291,16 @@ public class NotificationManagerUtils {
|
||||
* 构建电池提醒通知(全版本系统默认铃声+无振动)
|
||||
*/
|
||||
private Notification buildRemindNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildRemindNotification执行");
|
||||
if (context == null || message == null) {
|
||||
LogUtils.e(TAG, "buildRemindNotification failed: param is null");
|
||||
LogUtils.e(TAG, "buildRemindNotification失败:param is null | context=" + context + " | message=" + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : "电池状态提醒";
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : "电池状态异常,请及时处理";
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : REMIND_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : REMIND_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildRemindNotification:title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
@@ -309,7 +323,7 @@ public class NotificationManagerUtils {
|
||||
.setAutoCancel(true) // 点击关闭
|
||||
.setOngoing(false)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentIntent(createJumpPendingIntent(context, 1));
|
||||
.setContentIntent(createJumpPendingIntent(context, PENDING_INTENT_REQUEST_CODE_REMIND));
|
||||
|
||||
// API21+ 新增大图标+主题色
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
@@ -326,6 +340,7 @@ public class NotificationManagerUtils {
|
||||
* 创建跳转MainActivity的PendingIntent,API23+ 添加IMMUTABLE标记(避免安全异常)
|
||||
*/
|
||||
private PendingIntent createJumpPendingIntent(Context context, int requestCode) {
|
||||
LogUtils.d(TAG, "createJumpPendingIntent执行 | requestCode=" + requestCode);
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
@@ -333,9 +348,12 @@ public class NotificationManagerUtils {
|
||||
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
flags |= PendingIntent.FLAG_IMMUTABLE;
|
||||
LogUtils.d(TAG, "createJumpPendingIntent:添加FLAG_IMMUTABLE标记");
|
||||
}
|
||||
|
||||
return PendingIntent.getActivity(context, requestCode, intent, flags);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, flags);
|
||||
LogUtils.d(TAG, "createJumpPendingIntent成功 | requestCode=" + requestCode);
|
||||
return pendingIntent;
|
||||
}
|
||||
|
||||
// ================================== 内部辅助方法(获取APP图标,异常兜底)=================================
|
||||
@@ -343,11 +361,14 @@ public class NotificationManagerUtils {
|
||||
* 获取APP图标,失败返回默认图标
|
||||
*/
|
||||
private Bitmap getAppIcon(Context context) {
|
||||
LogUtils.d(TAG, "getAppIcon执行");
|
||||
try {
|
||||
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
return BitmapFactory.decodeResource(context.getResources(), pkgInfo.applicationInfo.icon);
|
||||
Bitmap appIcon = BitmapFactory.decodeResource(context.getResources(), pkgInfo.applicationInfo.icon);
|
||||
LogUtils.d(TAG, "getAppIcon成功:获取应用图标");
|
||||
return appIcon;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
LogUtils.e(TAG, "getAppIcon exception", e);
|
||||
LogUtils.e(TAG, "getAppIcon异常:获取应用图标失败,使用默认图标", e);
|
||||
return BitmapFactory.decodeResource(context.getResources(), NOTIFICATION_DEFAULT_ICON);
|
||||
}
|
||||
}
|
||||
@@ -362,11 +383,11 @@ public class NotificationManagerUtils {
|
||||
* 释放资源,销毁时调用
|
||||
*/
|
||||
public void release() {
|
||||
LogUtils.d(TAG, "release start");
|
||||
LogUtils.d(TAG, "release执行");
|
||||
cancelForegroundServiceNotify();
|
||||
mNotificationManager = null;
|
||||
mContext = null;
|
||||
LogUtils.d(TAG, "release success");
|
||||
LogUtils.d(TAG, "release成功:所有资源已释放");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user