电量提醒消息,通路架构基本完成。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Thu Dec 18 12:48:12 GMT 2025
|
||||
#Fri Dec 19 10:40:58 GMT 2025
|
||||
stageCount=10
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.9
|
||||
buildCount=42
|
||||
buildCount=43
|
||||
baseBetaVersion=15.14.10
|
||||
|
||||
@@ -155,8 +155,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
mMainContentView.releaseResources();
|
||||
mMainContentView = null;
|
||||
}
|
||||
// 销毁线程与Handler
|
||||
RemindThread.stopRemindThread();
|
||||
// 销毁Handler
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.removeCallbacksAndMessages(null);
|
||||
sGlobalHandler = null;
|
||||
|
||||
@@ -8,52 +8,59 @@ import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BatteryUtils;
|
||||
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* 控制中心广播接收器:监听电池状态变化、通知更新、线程启动指令,适配API29-30及小米手机
|
||||
* 控制中心广播接收器
|
||||
* 功能:监听电池状态变化、通知更新、线程启动指令
|
||||
* 适配:Java7 | API30 | 小米手机 | 内存泄漏防护
|
||||
*/
|
||||
public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// ====================== 常量定义(顶部统一管理,清晰易维护) ======================
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
public static final String TAG = ControlCenterServiceReceiver.class.getSimpleName();
|
||||
|
||||
// 广播Action常量(带包名前缀防冲突)
|
||||
public static final String ACTION_UPDATE_SERVICENOTIFICATION = "cc.winboll.studio.powerbell.action.UPDATE_SERVICENOTIFICATION";
|
||||
public static final String ACTION_START_REMINDTHREAD = "cc.winboll.studio.powerbell.action.START_REMINDTHREAD";
|
||||
public static final String EXTRA_APP_CONFIG_BEAN = "extra_app_config_bean";
|
||||
|
||||
// ====================== 成员变量(弱引用防泄漏,volatile保线程安全) ======================
|
||||
// 广播优先级常量
|
||||
private static final int BROADCAST_PRIORITY = IntentFilter.SYSTEM_HIGH_PRIORITY - 10;
|
||||
|
||||
// ================================== 成员变量区(弱引用防泄漏,volatile保线程安全)=================================
|
||||
private WeakReference<ControlCenterService> mwrControlCenterService;
|
||||
private static volatile int sLastBatteryLevel = -1;
|
||||
private static volatile boolean sIsCharging = false;
|
||||
|
||||
// ====================== 构造方法 ======================
|
||||
// ================================== 构造方法(初始化弱引用,避免内存泄漏)=================================
|
||||
public ControlCenterServiceReceiver(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "constructor: init receiver");
|
||||
LogUtils.d(TAG, "constructor: 初始化广播接收器 | service=" + service);
|
||||
this.mwrControlCenterService = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
// ====================== 广播核心接收逻辑 ======================
|
||||
// ================================== 广播核心接收逻辑(入口方法,分Action处理)=================================
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
LogUtils.d(TAG, "onReceive: enter, action=" + intent.getAction());
|
||||
LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null"));
|
||||
|
||||
// 基础参数校验
|
||||
if (context == null || intent == null || intent.getAction() == null) {
|
||||
LogUtils.e(TAG, "onReceive: invalid params");
|
||||
LogUtils.e(TAG, "onReceive: 参数无效,终止处理");
|
||||
return;
|
||||
}
|
||||
|
||||
// 弱引用获取服务,双重校验服务有效性(核心防护,避免内存泄漏+空指针)
|
||||
// 弱引用获取服务,双重校验服务有效性
|
||||
ControlCenterService service = mwrControlCenterService != null ? mwrControlCenterService.get() : null;
|
||||
if (service == null || service.isDestroyed()) {
|
||||
LogUtils.e(TAG, "onReceive: ControlCenterService is destroyed or null");
|
||||
// 服务销毁后主动注销广播,彻底避免无效回调
|
||||
LogUtils.e(TAG, "onReceive: 服务已销毁或为空,注销广播");
|
||||
unregisterAction(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// 分action处理逻辑
|
||||
// 分Action处理业务逻辑
|
||||
String action = intent.getAction();
|
||||
switch (action) {
|
||||
case ACTION_UPDATE_SERVICENOTIFICATION:
|
||||
@@ -63,238 +70,195 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
handleBatteryStateChanged(context, service, intent);
|
||||
break;
|
||||
case ACTION_START_REMINDTHREAD:
|
||||
handleStartRemindThread(service, intent);
|
||||
LogUtils.d(TAG, "onReceive: ACTION_START_REMINDTHREAD 逻辑待实现");
|
||||
break;
|
||||
default:
|
||||
LogUtils.w(TAG, "onReceive: unknown action=" + action);
|
||||
LogUtils.w(TAG, "onReceive: 未知Action=" + action);
|
||||
}
|
||||
LogUtils.d(TAG, "onReceive: exit");
|
||||
|
||||
LogUtils.d(TAG, "onReceive: 广播处理完成");
|
||||
}
|
||||
|
||||
// ====================== 业务逻辑方法(全链路容错+逻辑优化) ======================
|
||||
// ================================== 业务逻辑方法(按功能拆分,强化容错)=================================
|
||||
/**
|
||||
* 处理前台服务通知更新(强化非空校验,适配工具类最新逻辑)
|
||||
* 处理前台服务通知更新
|
||||
* @param service 控制中心服务实例
|
||||
*/
|
||||
private void handleUpdateServiceNotification(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "handleUpdateServiceNotification: start");
|
||||
LogUtils.d(TAG, "handleUpdateServiceNotification: 执行通知更新 | service=" + service);
|
||||
try {
|
||||
NotificationManagerUtils notifyUtils = service.getNotificationManager();
|
||||
NotificationMessage notifyMsg = service.getForegroundNotifyMsg();
|
||||
// 三重非空校验,避免工具类/消息/通知实例为空
|
||||
|
||||
// 非空校验+兜底重建
|
||||
if (notifyUtils == null || notifyMsg == null) {
|
||||
LogUtils.e(TAG, "handleUpdateServiceNotification: notify params null, rebuild notify first");
|
||||
// 兜底:通知实例为空时重建前台通知(适配工具类方法,避免空指针)
|
||||
if (notifyUtils != null) {
|
||||
notifyUtils.startForegroundServiceNotify(service, notifyMsg);
|
||||
}
|
||||
LogUtils.e(TAG, "handleUpdateServiceNotification: 通知工具类或消息为空");
|
||||
return;
|
||||
}
|
||||
// 调用工具类更新通知,确保方法匹配
|
||||
|
||||
notifyUtils.updateForegroundServiceNotify(notifyMsg);
|
||||
LogUtils.d(TAG, "handleUpdateServiceNotification: success");
|
||||
LogUtils.d(TAG, "handleUpdateServiceNotification: 通知更新成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleUpdateServiceNotification: failed", e);
|
||||
LogUtils.e(TAG, "handleUpdateServiceNotification: 通知更新失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理电池状态变化(核心适配 BatteryUtils,修复解析逻辑)
|
||||
* 处理电池状态变化广播
|
||||
* @param context 上下文
|
||||
* @param service 控制中心服务实例
|
||||
* @param intent 广播意图
|
||||
*/
|
||||
private void handleBatteryStateChanged(Context context, ControlCenterService service, Intent intent) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: start");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 处理电池状态变化 | context=" + context + " | service=" + service);
|
||||
try {
|
||||
// 1. 适配 BatteryUtils 工具类:统一解析电池状态(删除错误的 getTheQuantityOfElectricity)
|
||||
boolean currentCharging = BatteryUtils.isCharging(context); // 调用工具类判断充电状态
|
||||
int currentBatteryLevel = BatteryUtils.getCurrentBattery(context); // 调用工具类获取电量(0-100)
|
||||
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, 0), 100); // 二次校验,确保范围有效
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: current state - charging=" + currentCharging + ", level=" + currentBatteryLevel);
|
||||
// 1. 获取并校验当前电池状态
|
||||
boolean currentCharging = BatteryUtils.isCharging(context);
|
||||
int currentBatteryLevel = BatteryUtils.getCurrentBattery(context);
|
||||
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, 0), 100);
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 当前状态 | 充电=" + currentCharging + " | 电量=" + currentBatteryLevel);
|
||||
|
||||
// 2. 状态无变化直接跳过,减少无效运算
|
||||
// 2. 状态无变化则跳过,减少无效运算
|
||||
if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: no state change, skip");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态无变化,跳过处理");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 加载最新配置(容错:配置加载失败用服务当前配置兜底)
|
||||
// 3. 加载最新配置(多级兜底)
|
||||
AppConfigBean latestConfig = loadLatestConfig(context);
|
||||
if (latestConfig == null) {
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged: load latest config failed, use service current config");
|
||||
latestConfig = service.getCurrentConfigBean();
|
||||
// 服务配置也为空时,加载默认配置
|
||||
if (latestConfig == null) {
|
||||
latestConfig = new AppConfigBean();
|
||||
LogUtils.w(TAG, "handleBatteryStateChanged: 配置为空,使用默认配置");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 同步最新电池状态到配置,再更新服务配置(确保服务配置是最新的)
|
||||
// 4. 同步电池状态到配置,更新服务与线程
|
||||
latestConfig.setCurrentBatteryValue(currentBatteryLevel);
|
||||
latestConfig.setIsCharging(currentCharging);
|
||||
service.setCurrentConfigBean(latestConfig);
|
||||
service.notifyAppConfigUpdate(latestConfig);
|
||||
|
||||
// 5. 智能更新线程(线程已初始化则更新配置,未初始化则启动,避免重复重启)
|
||||
updateRemindThreadConfig(service, latestConfig, currentCharging, currentBatteryLevel);
|
||||
|
||||
// 6. 缓存最新状态(volatile变量确保多线程可见性)
|
||||
// 5. 缓存最新状态,确保多线程可见
|
||||
sIsCharging = currentCharging;
|
||||
sLastBatteryLevel = currentBatteryLevel;
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: success");
|
||||
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged: failed", e);
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged: 电池状态处理失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 内部辅助方法(拆分通用逻辑,统一管理)=================================
|
||||
/**
|
||||
* 处理线程启动指令(优化配置解析逻辑,强化线程启动容错)
|
||||
*/
|
||||
private void handleStartRemindThread(ControlCenterService service, Intent intent) {
|
||||
LogUtils.d(TAG, "handleStartRemindThread: start");
|
||||
try {
|
||||
// 安全解析配置(避免序列化异常)
|
||||
AppConfigBean appConfigBean = null;
|
||||
if (intent.hasExtra(EXTRA_APP_CONFIG_BEAN)) {
|
||||
Object configObj = intent.getSerializableExtra(EXTRA_APP_CONFIG_BEAN);
|
||||
if (configObj instanceof AppConfigBean) {
|
||||
appConfigBean = (AppConfigBean) configObj;
|
||||
// 配置补全:确保电池状态字段不为默认值(用缓存的最新状态)
|
||||
appConfigBean.setIsCharging(sIsCharging);
|
||||
appConfigBean.setCurrentBatteryValue(sLastBatteryLevel);
|
||||
}
|
||||
}
|
||||
|
||||
if (appConfigBean != null) {
|
||||
// 先更新服务配置,再重启线程(确保线程启动时拿到最新配置)
|
||||
service.setCurrentConfigBean(appConfigBean);
|
||||
// 重启线程(服务已实现安全重启逻辑,直接调用)
|
||||
service.restartRemindThreadSafely();
|
||||
LogUtils.d(TAG, "handleStartRemindThread: success, thread restarted with new config");
|
||||
} else {
|
||||
LogUtils.e(TAG, "handleStartRemindThread: appConfigBean is null or invalid");
|
||||
// 配置无效时,用缓存状态重启线程兜底
|
||||
service.restartRemindThreadSafely();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleStartRemindThread: failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 内部辅助方法(拆分逻辑+统一容错) ======================
|
||||
/**
|
||||
* 加载最新配置(适配AppConfigUtils单例逻辑,强化异常捕获)
|
||||
* 加载最新应用配置
|
||||
* @param context 上下文
|
||||
* @return 最新配置实例,失败返回null
|
||||
*/
|
||||
private AppConfigBean loadLatestConfig(Context context) {
|
||||
LogUtils.d(TAG, "loadLatestConfig: 加载最新配置 | context=" + context);
|
||||
try {
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "loadLatestConfig: context is null");
|
||||
LogUtils.e(TAG, "loadLatestConfig: 上下文为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
AppConfigUtils configUtils = AppConfigUtils.getInstance(context);
|
||||
if (configUtils == null) {
|
||||
LogUtils.e(TAG, "loadLatestConfig: AppConfigUtils instance is null");
|
||||
LogUtils.e(TAG, "loadLatestConfig: 配置工具类实例为空");
|
||||
return null;
|
||||
}
|
||||
// 强制重载配置,确保拿到最新用户设置
|
||||
|
||||
configUtils.reloadAllConfig();
|
||||
LogUtils.d(TAG, "loadLatestConfig: 配置加载成功");
|
||||
return configUtils.mAppConfigBean;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "loadLatestConfig: failed to load config", e);
|
||||
LogUtils.e(TAG, "loadLatestConfig: 配置加载失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 广播注册/注销(强化容错,避免重复操作)=================================
|
||||
/**
|
||||
* 更新提醒线程配置(智能判断线程状态,避免唤醒/启动冲突)
|
||||
* 注册广播接收器
|
||||
* @param context 上下文
|
||||
*/
|
||||
private void updateRemindThreadConfig(ControlCenterService service, AppConfigBean config, boolean isCharging, int batteryLevel) {
|
||||
try {
|
||||
RemindThread remindThread = service.getRemindThread();
|
||||
if (remindThread == null) {
|
||||
LogUtils.w(TAG, "updateRemindThreadConfig: remindThread is null, start thread first");
|
||||
// 线程未初始化,安全启动线程(服务方法已实现容错)
|
||||
service.restartRemindThreadSafely();
|
||||
return;
|
||||
}
|
||||
|
||||
// 先同步完整配置(核心:setAppConfigBean已包含状态同步,无需重复设置)
|
||||
remindThread.setAppConfigBean(config);
|
||||
//
|
||||
//
|
||||
// // 线程未运行时唤醒,已运行时无需操作(避免重复唤醒导致逻辑紊乱)
|
||||
// if (!remindThread.isRunning()) {
|
||||
// synchronized (remindThread) {
|
||||
// remindThread.notify();
|
||||
// LogUtils.d(TAG, "updateRemindThreadConfig: remindThread is woken up");
|
||||
// }
|
||||
// }
|
||||
LogUtils.d(TAG, "updateRemindThreadConfig: success, thread config updated");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "updateRemindThreadConfig: failed", e);
|
||||
// 配置更新失败时,重启线程兜底
|
||||
service.restartRemindThreadSafely();
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 广播注册/注销(强化容错,避免重复注册/注销) ======================
|
||||
public void registerAction(Context context) {
|
||||
LogUtils.d(TAG, "registerAction: start");
|
||||
LogUtils.d(TAG, "registerAction: 注册广播 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "registerAction: context is null");
|
||||
LogUtils.e(TAG, "registerAction: 上下文为空,注册失败");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 先注销再注册,避免重复注册导致异常
|
||||
// 先注销再注册,避免重复注册异常
|
||||
unregisterAction(context);
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_UPDATE_SERVICENOTIFICATION);
|
||||
filter.addAction(ACTION_START_REMINDTHREAD);
|
||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
// 优先级设置(低于系统最高优先级,避免被系统拦截)
|
||||
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 10);
|
||||
filter.setPriority(BROADCAST_PRIORITY);
|
||||
|
||||
context.registerReceiver(this, filter);
|
||||
LogUtils.d(TAG, "registerAction: success, broadcast receiver registered");
|
||||
LogUtils.d(TAG, "registerAction: 广播注册成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "registerAction: failed to register receiver", e);
|
||||
LogUtils.e(TAG, "registerAction: 广播注册失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销广播接收器
|
||||
* @param context 上下文
|
||||
*/
|
||||
public void unregisterAction(Context context) {
|
||||
LogUtils.d(TAG, "unregisterAction: start");
|
||||
LogUtils.d(TAG, "unregisterAction: 注销广播 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "unregisterAction: context is null");
|
||||
LogUtils.e(TAG, "unregisterAction: 上下文为空,注销失败");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 捕获注销异常(避免未注册时注销抛错)
|
||||
context.unregisterReceiver(this);
|
||||
LogUtils.d(TAG, "unregisterAction: success, broadcast receiver unregistered");
|
||||
LogUtils.d(TAG, "unregisterAction: 广播注销成功");
|
||||
} catch (IllegalArgumentException e) {
|
||||
LogUtils.w(TAG, "unregisterAction: receiver not registered, skip");
|
||||
LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "unregisterAction: failed to unregister receiver", e);
|
||||
LogUtils.e(TAG, "unregisterAction: 广播注销失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Getter方法(提供外部状态访问,强化线程安全) ======================
|
||||
public static int getLastBatteryLevel() {
|
||||
return sLastBatteryLevel;
|
||||
}
|
||||
|
||||
public static boolean isLastCharging() {
|
||||
return sIsCharging;
|
||||
}
|
||||
|
||||
// ====================== 主动释放资源(修复语法错误,彻底防泄漏) ======================
|
||||
// ================================== 资源释放与Getter方法(按需开放,防泄漏)=================================
|
||||
/**
|
||||
* 主动释放资源,避免内存泄漏
|
||||
*/
|
||||
public void release() {
|
||||
LogUtils.d(TAG, "release: receiver release resources");
|
||||
// 置空弱引用,帮助GC回收
|
||||
LogUtils.d(TAG, "release: 释放广播接收器资源");
|
||||
// 清空弱引用
|
||||
if (mwrControlCenterService != null) {
|
||||
mwrControlCenterService.clear();
|
||||
mwrControlCenterService = null;
|
||||
}
|
||||
// 重置静态状态缓存(修复重复赋值语法错误)
|
||||
// 重置静态状态缓存
|
||||
sLastBatteryLevel = -1;
|
||||
sIsCharging = false;
|
||||
LogUtils.d(TAG, "release: 资源释放完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次记录的电池电量
|
||||
* @return 电量值(0-100),未初始化返回-1
|
||||
*/
|
||||
public static int getLastBatteryLevel() {
|
||||
return sLastBatteryLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次记录的充电状态
|
||||
* @return true=充电中,false=未充电
|
||||
*/
|
||||
public static boolean isLastCharging() {
|
||||
return sIsCharging;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,148 +21,145 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 电池提醒核心服务
|
||||
* 功能:管理前台服务生命周期、控制提醒线程启停、处理配置更新
|
||||
* 适配:Java7 | API30 | 前台服务超时防护 | 电池优化忽略引导
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/17 15:48
|
||||
* @Describe 电池提醒核心服务:修复前台服务超时异常,优先在onCreate发送通知,适配Java7+API30
|
||||
*/
|
||||
public class ControlCenterService extends Service {
|
||||
// ================================== 静态常量(置顶统一管理,消除魔法值)=================================
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
public static final String TAG = "ControlCenterService";
|
||||
// 服务指令常量(带包名前缀,防止冲突)
|
||||
|
||||
// 服务指令常量(带包名前缀防冲突)
|
||||
public static final String ACTION_RESTART_REMIND_THREAD = "cc.winboll.studio.powerbell.action.RESTART_REMIND_THREAD";
|
||||
public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
|
||||
// 超时常量
|
||||
|
||||
// 超时/阈值常量
|
||||
private static final long THREAD_STOP_TIMEOUT = 1000L;
|
||||
|
||||
// ================================== 成员变量(按功能分类,私有封装)=================================
|
||||
// 服务控制核心
|
||||
// ================================== 成员变量区(按功能分层,volatile保证多线程可见性)=================================
|
||||
// 服务控制配置
|
||||
private ControlCenterServiceBean mServiceControlBean;
|
||||
// 业务核心组件
|
||||
private ControlCenterServiceHandler mServiceHandler;
|
||||
private RemindThread mRemindThread;
|
||||
private NotificationManagerUtils mNotificationManager;
|
||||
private AppConfigBean mCurrentConfigBean;
|
||||
private NotificationMessage mForegroundNotifyMsg;
|
||||
// 状态标记(volatile保证多线程可见性)
|
||||
// 服务状态标记
|
||||
private static volatile boolean isServiceRunning;
|
||||
private static volatile boolean mIsDestroyed;
|
||||
|
||||
// ================================== 服务生命周期方法(核心流程入口,按执行顺序排列)=================================
|
||||
// ================================== 服务生命周期方法(按执行顺序排列)=================================
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, "===== 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() : false) + " =====");
|
||||
LogUtils.d(TAG, "onCreate: 服务初始化完成 | 前台状态=" + isServiceRunning + " | 服务启用=" + (mServiceControlBean != null && mServiceControlBean.isEnableService()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "===== onStartCommand: 服务启动指令触发 =====");
|
||||
LogUtils.d(TAG, "onStartCommand: intent=" + intent + " | flags=" + flags + " | startId=" + startId);
|
||||
LogUtils.d(TAG, "onStartCommand: intent action=" + (intent != null ? intent.getAction() : "null"));
|
||||
LogUtils.d(TAG, "onStartCommand: 触发 | intent=" + intent + " | flags=" + flags + " | startId=" + startId);
|
||||
LogUtils.d(TAG, "onStartCommand: action=" + (intent != null ? intent.getAction() : "null"));
|
||||
|
||||
loadLatestServiceControlConfig();
|
||||
runCoreServiceLogic();
|
||||
|
||||
int returnFlag;
|
||||
if (mServiceControlBean != null && mServiceControlBean.isEnableService()) {
|
||||
LogUtils.d(TAG, "onStartCommand: 服务已启用,返回START_STICKY(被杀死后自动重启)");
|
||||
returnFlag = START_STICKY;
|
||||
} else {
|
||||
LogUtils.d(TAG, "onStartCommand: 服务未启用,返回默认值");
|
||||
returnFlag = super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
LogUtils.d(TAG, "===== onStartCommand: 服务启动指令处理完成 | 返回值=" + returnFlag + " =====");
|
||||
int returnFlag = (mServiceControlBean != null && mServiceControlBean.isEnableService())
|
||||
? START_STICKY
|
||||
: super.onStartCommand(intent, flags, startId);
|
||||
|
||||
LogUtils.d(TAG, "onStartCommand: 处理完成 | 返回策略=" + (returnFlag == START_STICKY ? "START_STICKY" : "DEFAULT"));
|
||||
return returnFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程启动 =====");
|
||||
LogUtils.d(TAG, "onDestroy: 服务销毁流程启动");
|
||||
super.onDestroy();
|
||||
// 顺序释放资源
|
||||
|
||||
// 资源释放顺序:前台服务 → 线程 → Handler → 通知 → 引用
|
||||
stopForegroundService();
|
||||
stopRemindThreadSafely();
|
||||
RemindThread.stopRemindThreadSafely();
|
||||
destroyHandler();
|
||||
releaseNotificationResource();
|
||||
clearAllReferences();
|
||||
// 重置核心状态标记
|
||||
|
||||
// 状态重置
|
||||
mCurrentConfigBean = null;
|
||||
mForegroundNotifyMsg = null;
|
||||
mServiceHandler = null;
|
||||
isServiceRunning = false;
|
||||
mIsDestroyed = true;
|
||||
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程完成 =====");
|
||||
|
||||
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
LogUtils.d(TAG, "onBind: 服务绑定请求 | intent=" + intent);
|
||||
LogUtils.d(TAG, "onBind: 绑定请求 | intent=" + intent);
|
||||
return null;
|
||||
}
|
||||
|
||||
// ================================== 核心业务逻辑(抽取独立方法,统一管理)=================================
|
||||
// ================================== 核心业务逻辑(独立抽取,统一调用)=================================
|
||||
/**
|
||||
* 抽取的服务核心运行逻辑,统一在onCreate和onStartCommand调用
|
||||
* 复用 isServiceRunning 做重复运行判断,避免重复初始化业务
|
||||
* 服务核心运行逻辑,在onCreate/onStartCommand复用
|
||||
* 避免重复初始化,保证前台服务优先启动
|
||||
*/
|
||||
private void runCoreServiceLogic() {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 开始执行核心业务逻辑");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 执行核心逻辑");
|
||||
loadLatestServiceControlConfig();
|
||||
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 服务启用状态=" + serviceEnabled + " | 当前运行状态=" + isServiceRunning + " | 已销毁状态=" + mIsDestroyed);
|
||||
|
||||
// 核心校验:服务已启用 + 服务未运行 + 未被销毁
|
||||
if (serviceEnabled) {
|
||||
if (!isServiceRunning && !mIsDestroyed) {
|
||||
isServiceRunning = true;
|
||||
mIsDestroyed = false;
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 满足执行条件,开始初始化前台通知和业务组件");
|
||||
// 优先发送前台通知,避免5秒超时异常
|
||||
if (initForegroundNotificationImmediately()) {
|
||||
loadDefaultConfig();
|
||||
initServiceBusinessLogic();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务组件初始化完成");
|
||||
} else {
|
||||
LogUtils.e(TAG, "runCoreServiceLogic: 前台通知初始化失败,终止核心业务执行");
|
||||
stopForegroundService();
|
||||
isServiceRunning = false;
|
||||
}
|
||||
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 服务启用=" + serviceEnabled + " | 已运行=" + isServiceRunning + " | 已销毁=" + mIsDestroyed);
|
||||
|
||||
if (serviceEnabled && !isServiceRunning && !mIsDestroyed) {
|
||||
isServiceRunning = true;
|
||||
mIsDestroyed = false;
|
||||
|
||||
if (initForegroundNotificationImmediately()) {
|
||||
loadDefaultConfig();
|
||||
initServiceBusinessLogic();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心组件初始化成功");
|
||||
} else {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务已运行或服务已销毁,无需重复执行");
|
||||
LogUtils.e(TAG, "runCoreServiceLogic: 前台通知初始化失败,终止业务");
|
||||
stopForegroundService();
|
||||
isServiceRunning = false;
|
||||
}
|
||||
} else {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 服务未启用,跳过核心业务执行");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic: 无需执行核心逻辑");
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 前台通知管理(优先执行,防止超时异常)=================================
|
||||
// ================================== 前台通知管理(优先执行,防止5秒超时)=================================
|
||||
/**
|
||||
* 立即初始化前台通知,内置兜底方案
|
||||
* @return true:通知初始化成功 false:通知初始化失败
|
||||
* 立即初始化前台通知,防止API26+前台服务超时异常
|
||||
* @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: 通知工具类初始化完成");
|
||||
}
|
||||
|
||||
if (mForegroundNotifyMsg == null) {
|
||||
mForegroundNotifyMsg = new NotificationMessage();
|
||||
mForegroundNotifyMsg.setTitle("电池监测服务");
|
||||
mForegroundNotifyMsg.setContent("后台运行中");
|
||||
mForegroundNotifyMsg.setRemindMSG("service_running");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知消息构建完成 | 标题=" + mForegroundNotifyMsg.getTitle() + " | 内容=" + mForegroundNotifyMsg.getContent());
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 通知消息构建完成");
|
||||
}
|
||||
|
||||
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
|
||||
ToastUtils.show("startForegroundServiceNotify 已调用");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功 | 通知ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程成功结束");
|
||||
ToastUtils.show("电池监测服务已启动");
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -171,36 +168,35 @@ 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);
|
||||
}
|
||||
LogUtils.d(TAG, "stopForegroundService: 停止前台服务流程结束");
|
||||
}
|
||||
|
||||
// ================================== 配置管理(本地持久化+内存同步)=================================
|
||||
/**
|
||||
* 读取本地最新服务控制配置
|
||||
* 加载本地最新服务控制配置
|
||||
*/
|
||||
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: 本地无配置文件,沿用当前内存配置 | 当前配置=" + mServiceControlBean);
|
||||
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无配置,沿用内存配置");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载默认应用配置
|
||||
* 加载默认业务配置(首次启动兜底)
|
||||
*/
|
||||
private void loadDefaultConfig() {
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 加载默认业务配置");
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置");
|
||||
if (mCurrentConfigBean == null) {
|
||||
mCurrentConfigBean = new AppConfigBean();
|
||||
mCurrentConfigBean.setEnableChargeReminder(true);
|
||||
@@ -208,287 +204,197 @@ public class ControlCenterService extends Service {
|
||||
mCurrentConfigBean.setEnableUsageReminder(true);
|
||||
mCurrentConfigBean.setUsageReminderValue(20);
|
||||
mCurrentConfigBean.setBatteryDetectInterval(1000);
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成 | 充电阈值=" + 80 + " | 耗电阈值=" + 20 + " | 检测间隔=" + 1000 + "ms");
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成 | 充电阈值=80 | 耗电阈值=20");
|
||||
} else {
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 内存中已有业务配置,无需加载默认值 | 当前充电阈值=" + mCurrentConfigBean.getChargeReminderValue());
|
||||
LogUtils.d(TAG, "loadDefaultConfig: 内存已有配置,无需加载");
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 业务组件初始化与销毁=================================
|
||||
/**
|
||||
* 初始化业务核心逻辑(Handler+线程)
|
||||
* 初始化Handler等核心业务组件
|
||||
*/
|
||||
private void initServiceBusinessLogic() {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程启动");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 初始化业务组件");
|
||||
if (mServiceHandler == null) {
|
||||
mServiceHandler = new ControlCenterServiceHandler(this);
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler初始化完成");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: Handler初始化完成");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler已存在,无需重复初始化");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: Handler已存在");
|
||||
}
|
||||
restartRemindThreadSafely();
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁Handler,移除所有消息和回调
|
||||
* 销毁Handler,移除所有消息和回调,防止内存泄漏
|
||||
*/
|
||||
private void destroyHandler() {
|
||||
LogUtils.d(TAG, "destroyHandler: Handler销毁流程启动");
|
||||
LogUtils.d(TAG, "destroyHandler: 销毁Handler");
|
||||
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实例为空");
|
||||
}
|
||||
LogUtils.d(TAG, "destroyHandler: Handler销毁流程结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放通知资源
|
||||
* 释放通知工具类资源
|
||||
*/
|
||||
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: 通知工具类实例为空");
|
||||
}
|
||||
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放流程结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 置空所有引用,防止内存泄漏
|
||||
*/
|
||||
private void clearAllReferences() {
|
||||
LogUtils.d(TAG, "clearAllReferences: 内存引用清理流程启动");
|
||||
LogUtils.d(TAG, "clearAllReferences: 清理内存引用");
|
||||
mForegroundNotifyMsg = null;
|
||||
mCurrentConfigBean = null;
|
||||
mServiceControlBean = null;
|
||||
LogUtils.d(TAG, "clearAllReferences: 所有业务引用已置空,防止内存泄漏");
|
||||
LogUtils.d(TAG, "clearAllReferences: 内存引用清理流程结束");
|
||||
LogUtils.d(TAG, "clearAllReferences: 引用清理完成");
|
||||
}
|
||||
|
||||
// ================================== 提醒线程管理(安全启停)=================================
|
||||
// ================================== 外部调用接口(静态方法,提供服务启停/配置更新入口)=================================
|
||||
/**
|
||||
* 安全重启提醒线程
|
||||
*/
|
||||
// public void restartRemindThreadSafely() {
|
||||
// LogUtils.d(TAG, "restartRemindThreadSafely: 线程重启流程启动");
|
||||
// // 停止旧线程
|
||||
// stopRemindThreadSafely();
|
||||
//
|
||||
// if (mServiceHandler != null) {
|
||||
// // 创建新线程实例
|
||||
// RemindThread.destroyInstance();
|
||||
// mRemindThread = RemindThread.getInstance(this, mServiceHandler);
|
||||
// LogUtils.d(TAG, "restartRemindThreadSafely: RemindThread新实例创建完成 | 线程引用=" + mRemindThread);
|
||||
// // 同步配置到线程
|
||||
// syncConfigToRemindThread();
|
||||
// // 启动线程
|
||||
// if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
|
||||
// try {
|
||||
// mRemindThread.start();
|
||||
// LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功 | 线程ID=" + mRemindThread.getId() + " | 线程名称=" + mRemindThread.getName());
|
||||
// } catch (IllegalThreadStateException e) {
|
||||
// LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常", e);
|
||||
// mRemindThread = null;
|
||||
// }
|
||||
// } else {
|
||||
// LogUtils.w(TAG, "restartRemindThreadSafely: 线程状态异常,跳过启动 | isAlive=" + (mRemindThread != null && mRemindThread.isAlive()) + " | isThreadStarted=" + (mRemindThread != null && mRemindThread.isThreadStarted()));
|
||||
// }
|
||||
// } else {
|
||||
// LogUtils.e(TAG, "restartRemindThreadSafely: mServiceHandler is null,线程启动失败");
|
||||
// }
|
||||
// LogUtils.d(TAG, "restartRemindThreadSafely: 线程重启流程结束");
|
||||
// }
|
||||
|
||||
/**
|
||||
* 安全停止提醒线程
|
||||
*/
|
||||
private void stopRemindThreadSafely() {
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止流程启动");
|
||||
if (mRemindThread == null) {
|
||||
LogUtils.w(TAG, "stopRemindThreadSafely: RemindThread实例为空,跳过停止流程");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (mRemindThread.isThreadStarted() || mRemindThread.isAlive()) {
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程处于运行状态,开始停止 | isThreadStarted=" + mRemindThread.isThreadStarted() + " | isAlive=" + mRemindThread.isAlive());
|
||||
mRemindThread.setIsReminding(false);
|
||||
mRemindThread.stopThread();
|
||||
// 等待线程终止,超时强制中断
|
||||
long waitStartTime = System.currentTimeMillis();
|
||||
while (mRemindThread.isAlive()) {
|
||||
if (System.currentTimeMillis() - waitStartTime > THREAD_STOP_TIMEOUT) {
|
||||
LogUtils.w(TAG, "stopRemindThreadSafely: 线程停止超时(超时时间=" + THREAD_STOP_TIMEOUT + "ms),强制中断");
|
||||
mRemindThread.interrupt();
|
||||
break;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止完成,耗时=" + (System.currentTimeMillis() - waitStartTime) + "ms");
|
||||
} else {
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程未运行,无需停止");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "stopRemindThreadSafely: 停止线程异常", e);
|
||||
} finally {
|
||||
mRemindThread = null;
|
||||
RemindThread.destroyInstance();
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程实例已置空,单例已销毁");
|
||||
}
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止流程结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步配置到提醒线程
|
||||
*/
|
||||
private void syncConfigToRemindThread() {
|
||||
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步流程启动");
|
||||
if (mRemindThread == null || mCurrentConfigBean == null) {
|
||||
LogUtils.e(TAG, "syncConfigToRemindThread: 配置同步失败 | mRemindThread=" + mRemindThread + " | mCurrentConfigBean=" + mCurrentConfigBean);
|
||||
return;
|
||||
}
|
||||
mRemindThread.setAppConfigBean(mCurrentConfigBean);
|
||||
|
||||
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步成功 | 充电阈值=" + mCurrentConfigBean.getChargeReminderValue() + " | 耗电阈值=" + mCurrentConfigBean.getUsageReminderValue() + " | 检测间隔=" + mCurrentConfigBean.getBatteryDetectInterval() + "ms");
|
||||
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步流程结束");
|
||||
}
|
||||
|
||||
// ================================== 静态工具方法(对外提供服务入口,按功能归类)=================================
|
||||
/**
|
||||
* 启动服务
|
||||
* 外部启动服务的统一入口
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void startControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用 =====");
|
||||
LogUtils.d(TAG, "startControlCenterService: 外部启动服务 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "startControlCenterService: Context为空,启动失败");
|
||||
return;
|
||||
}
|
||||
// 保存服务启动配置
|
||||
|
||||
// 保存启用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(true);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "startControlCenterService: 服务启动配置已保存 | 启用状态=" + controlBean.isEnableService());
|
||||
// 构建启动Intent
|
||||
|
||||
// 启动服务(区分API版本)
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
LogUtils.d(TAG, "startControlCenterService: SDK版本>=26,调用startForegroundService启动前台服务");
|
||||
context.startForegroundService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService: 以前台服务方式启动");
|
||||
} else {
|
||||
LogUtils.d(TAG, "startControlCenterService: SDK版本<26,调用startService启动普通服务");
|
||||
context.startService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService: 以普通服务方式启动");
|
||||
}
|
||||
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用完成 =====");
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* 外部停止服务的统一入口
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void stopControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, "===== stopControlCenterService: 外部停止服务接口调用 =====");
|
||||
LogUtils.d(TAG, "stopControlCenterService: 外部停止服务 | context=" + context);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "stopControlCenterService: Context为空,停止失败");
|
||||
return;
|
||||
}
|
||||
// 保存服务停止配置
|
||||
|
||||
// 保存停用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "stopControlCenterService: 服务停止配置已保存 | 启用状态=" + controlBean.isEnableService());
|
||||
// 构建停止Intent
|
||||
|
||||
// 停止服务
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
LogUtils.d(TAG, "stopControlCenterService: 调用stopService发送停止指令");
|
||||
context.stopService(intent);
|
||||
LogUtils.d(TAG, "===== stopControlCenterService: 外部停止服务接口调用完成 =====");
|
||||
LogUtils.d(TAG, "stopControlCenterService: 停止指令已发送");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新业务配置并触发线程重启
|
||||
* 外部更新配置并触发线程重启
|
||||
* @param context 上下文
|
||||
* @param configBean 新配置
|
||||
*/
|
||||
public static void updateStatus(Context context, AppConfigBean configBean) {
|
||||
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用 =====");
|
||||
LogUtils.d(TAG, "updateStatus: 外部更新配置 | context=" + context + " | config=" + configBean);
|
||||
if (context == null || configBean == null) {
|
||||
LogUtils.e(TAG, "updateStatus: 参数为空 | context=" + context + " | configBean=" + configBean);
|
||||
LogUtils.e(TAG, "updateStatus: 参数为空,更新失败");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "updateStatus: 待同步配置 | 充电阈值=" + configBean.getChargeReminderValue() + " | 耗电阈值=" + configBean.getUsageReminderValue());
|
||||
// 构建配置更新Intent
|
||||
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
intent.setAction(ACTION_RESTART_REMIND_THREAD);
|
||||
intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
LogUtils.d(TAG, "updateStatus: SDK版本>=26,调用startForegroundService发送配置更新指令");
|
||||
context.startForegroundService(intent);
|
||||
} else {
|
||||
LogUtils.d(TAG, "updateStatus: SDK版本<26,调用startService发送配置更新指令");
|
||||
context.startService(intent);
|
||||
}
|
||||
LogUtils.d(TAG, "updateStatus: 配置更新指令发送成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "updateStatus: 发送配置更新指令异常", e);
|
||||
LogUtils.e(TAG, "updateStatus: 发送指令异常", e);
|
||||
}
|
||||
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用完成 =====");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并引导用户开启忽略电池优化
|
||||
* 检查并引导用户开启忽略电池优化(API23+)
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void checkIgnoreBatteryOptimization(Context context) {
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 电池优化检查流程启动");
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 检查电池优化 | context=" + context);
|
||||
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization: 无需检查 | context=" + context + " | SDK版本=" + (Build.VERSION.SDK_INT));
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization: 无需检查");
|
||||
return;
|
||||
}
|
||||
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (powerManager == null) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: PowerManager获取失败");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String packageName = context.getPackageName();
|
||||
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
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: 已跳转至系统设置页,引导用户开启忽略电池优化");
|
||||
} else {
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已开启忽略电池优化,无需引导");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化异常", e);
|
||||
|
||||
String packageName = context.getPackageName();
|
||||
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
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: 已跳转至系统设置页");
|
||||
}
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 电池优化检查流程结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断服务是否运行(适配API30+)
|
||||
* 检查服务是否运行(适配API30+)
|
||||
* @param context 上下文
|
||||
* @param serviceClass 服务类
|
||||
* @return true=运行中 false=未运行
|
||||
*/
|
||||
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程启动 | serviceClass=" + (serviceClass != null ? serviceClass.getName() : "null"));
|
||||
LogUtils.d(TAG, "isServiceRunning: 检查服务状态 | context=" + context + " | service=" + serviceClass);
|
||||
if (context == null || serviceClass == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning: 参数为空 | context=" + context + " | serviceClass=" + serviceClass);
|
||||
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
|
||||
LogUtils.e(TAG, "isServiceRunning: 参数为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (am == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败");
|
||||
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isRunning = false;
|
||||
String packageName = context.getPackageName();
|
||||
String serviceClassName = serviceClass.getName();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
LogUtils.d(TAG, "isServiceRunning: SDK版本>=30,使用进程信息判断");
|
||||
String packageName = context.getPackageName();
|
||||
// API30+ 禁止获取其他应用服务,通过进程状态判断
|
||||
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
|
||||
if (processes != null) {
|
||||
for (ActivityManager.RunningAppProcessInfo process : processes) {
|
||||
@@ -496,67 +402,64 @@ public class ControlCenterService extends Service {
|
||||
(process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE ||
|
||||
process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)) {
|
||||
isRunning = true;
|
||||
LogUtils.d(TAG, "isServiceRunning: 检测到前台服务进程,判定服务运行");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isRunning) {
|
||||
LogUtils.d(TAG, "isServiceRunning: API30+未检测到运行,执行兜底判断");
|
||||
isRunning = isServiceStarted(context, serviceClass);
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceRunning: API30+ 判断结果=" + isRunning);
|
||||
} else {
|
||||
LogUtils.d(TAG, "isServiceRunning: SDK版本<30,使用服务列表判断");
|
||||
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);
|
||||
if (runningServices != null) {
|
||||
String serviceClassName = serviceClass.getName();
|
||||
for (ActivityManager.RunningServiceInfo info : runningServices) {
|
||||
// API30- 通过服务列表判断
|
||||
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(100);
|
||||
if (services != null) {
|
||||
for (ActivityManager.RunningServiceInfo info : services) {
|
||||
if (serviceClassName.equals(info.service.getClassName())) {
|
||||
isRunning = true;
|
||||
LogUtils.d(TAG, "isServiceRunning: 检测到服务在运行列表中,判定服务运行");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceRunning: API30- 判断结果=" + isRunning);
|
||||
}
|
||||
|
||||
// 兜底判断:配置启用状态
|
||||
if (!isRunning) {
|
||||
isRunning = isServiceStarted(context, serviceClass);
|
||||
LogUtils.d(TAG, "isServiceRunning: 兜底判断结果=" + isRunning);
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=" + isRunning);
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底判断服务是否已启动
|
||||
* 兜底判断服务是否已启动(通过配置文件)
|
||||
*/
|
||||
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程启动");
|
||||
boolean result = false;
|
||||
LogUtils.d(TAG, "isServiceStarted: 兜底判断服务状态");
|
||||
try {
|
||||
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
|
||||
result = controlBean != null && controlBean.isEnableService();
|
||||
LogUtils.d(TAG, "isServiceStarted: 兜底判断结果=" + result + " | 配置启用状态=" + (controlBean != null ? controlBean.isEnableService() : "null"));
|
||||
return controlBean != null && controlBean.isEnableService();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "isServiceStarted: 兜底判断异常", e);
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程结束 | 结果=" + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ================================== Getter/Setter 方法(添加日志)=================================
|
||||
public RemindThread getRemindThread() {
|
||||
return mRemindThread;
|
||||
}
|
||||
|
||||
public void setCurrentConfigBean(AppConfigBean configBean) {
|
||||
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新接口调用");
|
||||
if (configBean == null) {
|
||||
LogUtils.e(TAG, "setCurrentConfigBean: 待更新配置为空,更新失败");
|
||||
return;
|
||||
// ================================== 业务方法(配置更新)=================================
|
||||
/**
|
||||
* 接收外部配置更新,同步到提醒线程
|
||||
* @param latestConfig 最新配置
|
||||
*/
|
||||
public void notifyAppConfigUpdate(AppConfigBean latestConfig) {
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate: 配置更新 | config=" + latestConfig);
|
||||
if (latestConfig != null && mServiceHandler != null) {
|
||||
mCurrentConfigBean = latestConfig;
|
||||
RemindThread.startRemindThread(this, mServiceHandler, latestConfig);
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate: 配置已同步到线程");
|
||||
} else {
|
||||
LogUtils.e(TAG, "notifyAppConfigUpdate: 参数为空,同步失败");
|
||||
}
|
||||
this.mCurrentConfigBean = configBean;
|
||||
syncConfigToRemindThread();
|
||||
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新完成 | 新充电阈值=" + configBean.getChargeReminderValue());
|
||||
}
|
||||
|
||||
// ================================== Getter 方法(按需开放,避免冗余Setter)=================================
|
||||
public ControlCenterServiceBean getServiceControlBean() {
|
||||
return mServiceControlBean;
|
||||
}
|
||||
|
||||
@@ -11,38 +11,34 @@ import java.lang.ref.WeakReference;
|
||||
* 提醒线程(单例模式)
|
||||
* 功能:统一管理充电/耗电提醒逻辑,发送提醒时携带当前电量+充电状态
|
||||
* 适配:Java7 | API30 | 小米手机
|
||||
* 特性:线程安全、内存泄漏防护、配置重试兜底
|
||||
* 对外接口:仅保留 {@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)} 和 {@link #stopRemindThread()}
|
||||
* 特性:线程安全、内存泄漏防护、配置参数校验
|
||||
* 对外接口:{@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)}、{@link #stopRemindThreadSafely()}
|
||||
*/
|
||||
public class RemindThread extends Thread {
|
||||
// ================================== 静态常量(置顶归类,消除魔法值)=================================
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
public static final String TAG = "RemindThread";
|
||||
|
||||
// 时间常量 (ms)
|
||||
private static final long INIT_DELAY_TIME = 500L;
|
||||
private static final int MIN_SLEEP_TIME = 500;
|
||||
private static final int DEFAULT_SLEEP_TIME = 1000;
|
||||
private static final long REMIND_INTERVAL = 3000L;
|
||||
private static final long THREAD_JOIN_TIMEOUT = 1000L;
|
||||
|
||||
// 重试与状态常量
|
||||
private static final int CONFIG_RETRY_MAX = 3;
|
||||
// 状态常量
|
||||
private static final int INVALID_BATTERY_VALUE = -1;
|
||||
|
||||
// ================================== 单例核心(线程安全,双重校验锁)=================================
|
||||
private static volatile RemindThread sInstance;
|
||||
|
||||
// ================================== 成员变量(按功能分层,volatile保证多线程可见性,防内存泄漏)=================================
|
||||
// 弱引用依赖(避免内存泄漏)
|
||||
// ================================== 成员变量区(按功能分层,volatile保证多线程可见性)=================================
|
||||
// 弱引用依赖(防内存泄漏)
|
||||
private Context mContext;
|
||||
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
|
||||
|
||||
// 线程状态标记(volatile 保证多线程可见性)
|
||||
// 线程状态标记
|
||||
private volatile boolean isExist;
|
||||
//private volatile boolean isThreadStarted;
|
||||
private volatile boolean isReminding;
|
||||
//private volatile boolean isRemindTimerRunning;
|
||||
|
||||
// 业务配置参数(范围校验,实时同步)
|
||||
// 业务配置参数
|
||||
private volatile boolean isEnableChargeReminder;
|
||||
private volatile boolean isEnableUsageReminder;
|
||||
private volatile long sleepTime;
|
||||
@@ -51,174 +47,176 @@ public class RemindThread extends Thread {
|
||||
private volatile int quantityOfElectricity;
|
||||
private volatile boolean isCharging;
|
||||
|
||||
// 辅助变量(并发安全+防重复提醒)
|
||||
//private volatile long lastRemindTime;
|
||||
// 并发安全锁
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// ================================== 私有构造器(单例专用,初始化状态+防护泄漏)=================================
|
||||
// ================================== 私有构造器(单例专用,禁止外部实例化)=================================
|
||||
private RemindThread(Context context, ControlCenterServiceHandler handler) {
|
||||
LogUtils.d(TAG, "构造线程实例 | threadName=" + getName() + " | threadId=" + getId());
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
|
||||
resetThreadStateInternal();
|
||||
LogUtils.d(TAG, "构造线程实例 | threadName=" + getName() + " | threadId=" + getId());
|
||||
}
|
||||
|
||||
// ================================== 对外公开静态方法(仅保留两个:启动+停止)=================================
|
||||
// ================================== 单例获取方法(核心,统一管理单例创建)=================================
|
||||
/**
|
||||
* 对外启动线程接口
|
||||
* 私有单例获取方法,双重校验锁保证线程安全
|
||||
* @param context 上下文
|
||||
* @param handler 服务处理器
|
||||
* @param config 应用配置Bean
|
||||
* @return 若 isReminding 为 true 直接返回 true;否则创建/启动线程后返回 false
|
||||
* @return 唯一的 RemindThread 实例
|
||||
*/
|
||||
private static RemindThread getInstance(Context context, ControlCenterServiceHandler handler) {
|
||||
LogUtils.d(TAG, "getInstance: 获取单例 | context=" + context + " | handler=" + handler);
|
||||
if (sInstance == null) {
|
||||
synchronized (RemindThread.class) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new RemindThread(context, handler);
|
||||
LogUtils.d(TAG, "getInstance: 新建单例成功 | threadId=" + sInstance.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
// ================================== 对外公开静态接口(全部基于单例实现)=================================
|
||||
/**
|
||||
* 启动提醒线程(基于单例操作,确保全局唯一)
|
||||
* @param context 上下文(非空)
|
||||
* @param handler 服务处理器(非空)
|
||||
* @param config 应用配置Bean(非空)
|
||||
* @return true: isReminding为真/线程启动成功;false: 入参非法/启动失败
|
||||
*/
|
||||
public static boolean startRemindThread(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
|
||||
LogUtils.d(TAG, "startRemindThread: 调用 | context=" + context + " | handler=" + handler + " | config=" + config);
|
||||
// 入参校验
|
||||
if (context == null || handler == null || config == null) {
|
||||
LogUtils.e(TAG, "startRemindThread: 入参为空,启动失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. 若 isReminding 为真,直接返回 true 无需操作
|
||||
if (sInstance != null && sInstance.isReminding) {
|
||||
// 3. 同步配置
|
||||
sInstance.setAppConfigBean(config);
|
||||
LogUtils.d(TAG, "startRemindThread: isReminding 为真,更新最新数据后返回");
|
||||
// 获取单例
|
||||
RemindThread instance = getInstance(context, handler);
|
||||
|
||||
// 已在提醒状态,同步配置后返回
|
||||
if (instance.isReminding) {
|
||||
instance.setAppConfigBean(config);
|
||||
LogUtils.d(TAG, "startRemindThread: 线程已在提醒状态,同步最新配置 | threadId=" + instance.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. 未创建实例则创建
|
||||
if (sInstance == null) {
|
||||
synchronized (RemindThread.class) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new RemindThread(context, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4. 线程未运行则启动
|
||||
if (!sInstance.isRunning()) {
|
||||
sInstance.isExist = false; // 重置退出标记
|
||||
sInstance.start();
|
||||
LogUtils.d(TAG, "startRemindThread: 线程启动成功 | threadId=" + sInstance.getId());
|
||||
// 同步配置并启动线程
|
||||
instance.setAppConfigBean(config);
|
||||
if (!instance.isRunning()) {
|
||||
instance.isExist = false;
|
||||
instance.start();
|
||||
LogUtils.d(TAG, "startRemindThread: 线程启动成功 | threadId=" + instance.getId());
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.d(TAG, "startRemindThread: 线程已在运行 | threadId=" + sInstance.getId());
|
||||
LogUtils.d(TAG, "startRemindThread: 线程已在运行 | threadId=" + instance.getId());
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外停止线程接口:直接销毁单例
|
||||
* 安全停止线程(基于单例操作,优雅销毁唯一实例)
|
||||
*/
|
||||
public static void stopRemindThread() {
|
||||
LogUtils.d(TAG, "stopRemindThread: 开始停止线程");
|
||||
destroyInstance();
|
||||
LogUtils.d(TAG, "stopRemindThread: 线程已停止并销毁");
|
||||
public static void stopRemindThreadSafely() {
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 调用 | sInstance=" + (sInstance != null));
|
||||
synchronized (RemindThread.class) {
|
||||
if (sInstance == null) {
|
||||
LogUtils.w(TAG, "stopRemindThreadSafely: 线程实例为空,无需停止");
|
||||
return;
|
||||
}
|
||||
|
||||
// 线程未运行,直接销毁
|
||||
if (!sInstance.isRunning()) {
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程未运行,直接销毁 | threadId=" + sInstance.getId());
|
||||
destroyInstance();
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记退出,等待线程自然结束
|
||||
sInstance.isExist = true;
|
||||
sInstance.isReminding = false;
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 标记线程退出 | threadId=" + sInstance.getId());
|
||||
|
||||
try {
|
||||
sInstance.join(THREAD_JOIN_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LogUtils.e(TAG, "stopRemindThreadSafely: 等待线程退出被中断", e);
|
||||
}
|
||||
|
||||
// 销毁单例
|
||||
destroyInstance();
|
||||
LogUtils.d(TAG, "stopRemindThreadSafely: 线程安全销毁完成");
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 私有单例管理方法(内部使用)=================================
|
||||
// ================================== 私有单例管理方法=================================
|
||||
/**
|
||||
* 获取单例实例(私有化,仅内部调用)
|
||||
*/
|
||||
// private static RemindThread getInstance(Context context, ControlCenterServiceHandler handler) {
|
||||
// LogUtils.d(TAG, "getInstance: 尝试获取单例 | currentInstance=" + (sInstance != null ? "存在" : "不存在"));
|
||||
//
|
||||
// if (context == null || handler == null) {
|
||||
// LogUtils.e(TAG, "getInstance: 入参为空");
|
||||
// throw new IllegalArgumentException("Context and ControlCenterServiceHandler cannot be null");
|
||||
// }
|
||||
//
|
||||
// if (sInstance != null && !sInstance.isRunning()) {
|
||||
// destroyInstance();
|
||||
// LogUtils.d(TAG, "getInstance: 旧线程已停止,销毁单例");
|
||||
// }
|
||||
//
|
||||
// if (sInstance == null) {
|
||||
// synchronized (RemindThread.class) {
|
||||
// if (sInstance == null) {
|
||||
// sInstance = new RemindThread(context, handler);
|
||||
// LogUtils.d(TAG, "getInstance: 新线程实例创建成功 | threadId=" + sInstance.getId());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return sInstance;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 销毁单例(安全停止线程+释放资源,避免内存泄漏)
|
||||
* 销毁单例,安全释放资源
|
||||
*/
|
||||
private static void destroyInstance() {
|
||||
LogUtils.d(TAG, "destroyInstance: 开始销毁线程单例");
|
||||
LogUtils.d(TAG, "destroyInstance: 开始销毁单例 | sInstance=" + (sInstance != null));
|
||||
synchronized (RemindThread.class) {
|
||||
if (sInstance != null) {
|
||||
// 终止线程并释放资源
|
||||
sInstance.isExist = true;
|
||||
//sInstance.isRemindTimerRunning = false;
|
||||
sInstance.isReminding = false;
|
||||
if (sInstance.isAlive()) {
|
||||
sInstance.interrupt();
|
||||
LogUtils.d(TAG, "destroyInstance: 线程已中断");
|
||||
LogUtils.d(TAG, "destroyInstance: 线程已中断 | threadId=" + sInstance.getId());
|
||||
}
|
||||
sInstance.releaseResourcesInternal();
|
||||
sInstance = null;
|
||||
sInstance.isReminding = false;
|
||||
LogUtils.d(TAG, "destroyInstance: 线程单例销毁完成");
|
||||
LogUtils.d(TAG, "destroyInstance: 单例销毁完成");
|
||||
} else {
|
||||
LogUtils.w(TAG, "destroyInstance: 单例已为空,跳过销毁");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 线程核心逻辑(run方法,高效退出+异常容错,仅此处保留mLock)=================================
|
||||
// ================================== 线程核心运行逻辑=================================
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "run: 线程启动 | threadId=" + Thread.currentThread().getId() + " | state=" + getState());
|
||||
|
||||
// 仅保留此处的mLock,保护isReminding等核心状态的读写,防止线程重复启动
|
||||
// 初始化提醒状态(加锁保护)
|
||||
synchronized (mLock) {
|
||||
if (isExist && !isReminding) {
|
||||
isReminding = true;
|
||||
if (!isExist && !isReminding) {
|
||||
isReminding = true;
|
||||
LogUtils.d(TAG, "run: 初始化提醒状态成功 | isReminding=true");
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("线程退出,标志位:isExist %s, isReminding %s.", isExist, isReminding));
|
||||
}
|
||||
LogUtils.d(TAG, "run: 线程退出条件满足 | isExist=" + isExist + " | isReminding=" + isReminding);
|
||||
cleanThreadStateInternal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 核心检测循环(快速退出+并发安全)
|
||||
// 核心检测循环
|
||||
LogUtils.d(TAG, "run: 进入电量检测循环 | sleepTime=" + sleepTime + "ms");
|
||||
while (!isExist) {
|
||||
try {
|
||||
// 快速退出判断
|
||||
if (isExist) break;
|
||||
|
||||
// 核心防护:电量无效退出
|
||||
if ((quantityOfElectricity == INVALID_BATTERY_VALUE)
|
||||
break;
|
||||
}
|
||||
|
||||
// 电量超出范围退出
|
||||
// 电量有效性校验
|
||||
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
||||
LogUtils.w(TAG, "run: 电量无效,修正为无效值 | currentBattery=" + quantityOfElectricity);
|
||||
LogUtils.w(TAG, "run: 电量无效,退出循环 | currentBattery=" + quantityOfElectricity);
|
||||
break;
|
||||
}
|
||||
|
||||
// 防重复提醒(间隔未到/计时器运行中,依赖volatile保证可见性)
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastRemindTime < REMIND_INTERVAL) || isRemindTimerRunning) {
|
||||
safeSleepInternal(sleepTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 充电提醒触发
|
||||
// 充电提醒触发逻辑
|
||||
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
|
||||
LogUtils.d(TAG, "run: 循环检测触发充电提醒 | battery=" + quantityOfElectricity + " ≥ threshold=" + chargeReminderValue);
|
||||
LogUtils.d(TAG, "run: 触发充电提醒 | battery=" + quantityOfElectricity + " ≥ threshold=" + chargeReminderValue);
|
||||
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
|
||||
lastRemindTime = currentTime;
|
||||
startRemindRecoveryTimerInternal();
|
||||
} else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
|
||||
LogUtils.d(TAG, "run: 循环检测触发耗电提醒 | battery=" + quantityOfElectricity + " ≤ threshold=" + usageReminderValue);
|
||||
LogUtils.d(TAG, "run: 触发耗电提醒 | battery=" + quantityOfElectricity + " ≤ threshold=" + usageReminderValue);
|
||||
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
|
||||
lastRemindTime = currentTime;
|
||||
startRemindRecoveryTimerInternal();
|
||||
}
|
||||
|
||||
// 安全休眠
|
||||
safeSleepInternal(sleepTime);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "run: 线程运行异常,休眠重试", e);
|
||||
@@ -226,57 +224,28 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
// 退出清理
|
||||
// 循环退出,清理状态
|
||||
cleanThreadStateInternal();
|
||||
LogUtils.d(TAG, "run: 线程循环退出 | threadId=" + Thread.currentThread().getId());
|
||||
}
|
||||
|
||||
// ================================== 核心业务辅助方法(全部私有化,移除对外访问)=================================
|
||||
// ================================== 内部业务辅助方法=================================
|
||||
/**
|
||||
* 配置同步重试(确保阈值有效,失败兜底)
|
||||
*/
|
||||
// private boolean syncConfigRetry() {
|
||||
// LogUtils.d(TAG, "syncConfigRetry: 开始配置同步 | maxRetry=" + CONFIG_RETRY_MAX);
|
||||
// int retryCount = 0;
|
||||
//
|
||||
// while (retryCount < CONFIG_RETRY_MAX) {
|
||||
// boolean chargeValid = chargeReminderValue >= 0 && chargeReminderValue <= 100;
|
||||
// boolean usageValid = usageReminderValue >= 0 && usageReminderValue <= 100;
|
||||
// if (chargeValid && usageValid) {
|
||||
// LogUtils.d(TAG, "syncConfigRetry: 配置同步成功 | retryCount=" + retryCount);
|
||||
// return true;
|
||||
// }
|
||||
// LogUtils.w(TAG, "syncConfigRetry: 配置未同步,重试 | retryCount=" + (retryCount + 1));
|
||||
// try {
|
||||
// Thread.sleep(1000);
|
||||
// retryCount++;
|
||||
// } catch (InterruptedException e) {
|
||||
// Thread.currentThread().interrupt();
|
||||
// LogUtils.e(TAG, "syncConfigRetry: 配置重试被中断", e);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 兜底默认阈值
|
||||
// chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
|
||||
// usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
|
||||
// quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
// LogUtils.e(TAG, "syncConfigRetry: 配置重试失败,使用兜底阈值 | chargeThreshold=" + chargeReminderValue + " | usageThreshold=" + usageReminderValue);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 发送提醒消息(携带当前电量+充电状态,弱引用Handler+Message复用,防泄漏)
|
||||
* 发送提醒消息(内部方法,弱引用Handler防泄漏)
|
||||
* @param type 提醒类型:+充电/-耗电
|
||||
* @param battery 当前电量
|
||||
* @param isCharging 充电状态
|
||||
*/
|
||||
private void sendNotificationMessageInternal(String type, int battery, boolean isCharging) {
|
||||
LogUtils.d(TAG, "sendNotificationMessageInternal: 准备发送提醒 | type=" + type + " | battery=" + battery + " | isCharging=" + isCharging);
|
||||
|
||||
LogUtils.d(TAG, "sendNotificationMessageInternal: 调用 | type=" + type + " | battery=" + battery + " | isCharging=" + isCharging);
|
||||
// 前置校验
|
||||
if (isExist || !isReminding) {
|
||||
LogUtils.d(TAG, "sendNotificationMessageInternal: 线程退出或提醒关闭,跳过发送");
|
||||
return;
|
||||
}
|
||||
|
||||
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler != null ? mwrControlCenterServiceHandler.get() : null;
|
||||
// 获取Handler并发送消息
|
||||
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler.get();
|
||||
if (handler == null) {
|
||||
LogUtils.w(TAG, "sendNotificationMessageInternal: Handler已回收,发送失败");
|
||||
return;
|
||||
@@ -297,51 +266,8 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动提醒恢复计时器(防重复提醒,弱引用线程)
|
||||
*/
|
||||
private void startRemindRecoveryTimerInternal() {
|
||||
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 启动提醒恢复计时器 | interval=" + REMIND_INTERVAL + "ms");
|
||||
if (isExist || isRemindTimerRunning || sInstance != this) {
|
||||
LogUtils.w(TAG, "startRemindRecoveryTimerInternal: 计时器启动条件不满足");
|
||||
return;
|
||||
}
|
||||
isReminding = false;
|
||||
isRemindTimerRunning = true;
|
||||
|
||||
final WeakReference<RemindThread> threadRef = new WeakReference<>(this);
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(REMIND_INTERVAL);
|
||||
RemindThread thread = threadRef.get();
|
||||
|
||||
if (thread == null || thread.isExist || sInstance != thread) {
|
||||
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 线程已销毁,不恢复提醒");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean canRecover = !thread.isExist && sInstance == thread && (thread.isEnableChargeReminder || thread.isEnableUsageReminder);
|
||||
if (canRecover) {
|
||||
thread.isReminding = true;
|
||||
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒功能恢复开启");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LogUtils.e(TAG, "startRemindRecoveryTimerInternal: 计时器被中断", e);
|
||||
} finally {
|
||||
RemindThread thread = threadRef.get();
|
||||
if (thread != null && sInstance == thread) {
|
||||
thread.isRemindTimerRunning = false;
|
||||
}
|
||||
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒恢复计时器执行完成");
|
||||
}
|
||||
}
|
||||
}, "RemindRecoveryTimer").start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全休眠(保留中断标记,确保退出逻辑生效)
|
||||
* 安全休眠(保留中断标记,确保线程可退出)
|
||||
* @param millis 休眠时长
|
||||
*/
|
||||
private void safeSleepInternal(long millis) {
|
||||
try {
|
||||
@@ -353,29 +279,14 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理线程运行状态(退出后重置所有标记)
|
||||
*/
|
||||
private void cleanThreadStateInternal() {
|
||||
LogUtils.d(TAG, "cleanThreadStateInternal: 清理线程运行状态");
|
||||
isReminding = false;
|
||||
isExist = true;
|
||||
isThreadStarted = false;
|
||||
isRemindTimerRunning = false;
|
||||
lastRemindTime = 0;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
if (isAlive()) interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始状态重置(构造器专用)
|
||||
* 重置线程初始状态(构造器专用)
|
||||
*/
|
||||
private void resetThreadStateInternal() {
|
||||
LogUtils.d(TAG, "resetThreadStateInternal: 重置线程初始状态");
|
||||
// 状态标记
|
||||
isExist = false;
|
||||
isReminding = false;
|
||||
isThreadStarted = false;
|
||||
isRemindTimerRunning = false;
|
||||
lastRemindTime = 0;
|
||||
// 配置参数
|
||||
isEnableChargeReminder = false;
|
||||
isEnableUsageReminder = false;
|
||||
sleepTime = DEFAULT_SLEEP_TIME;
|
||||
@@ -386,23 +297,38 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步应用配置(参数校验+范围限制,立即生效)
|
||||
* 清理线程运行状态(退出循环专用)
|
||||
*/
|
||||
private void cleanThreadStateInternal() {
|
||||
LogUtils.d(TAG, "cleanThreadStateInternal: 清理线程运行状态");
|
||||
isReminding = false;
|
||||
isExist = true;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
if (isAlive()) {
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步应用配置(参数范围校验,确保有效性)
|
||||
* @param config 应用配置Bean
|
||||
*/
|
||||
public void setAppConfigBean(AppConfigBean config) {
|
||||
LogUtils.d(TAG, "setAppConfigBean: 开始同步应用配置 | config=" + config);
|
||||
LogUtils.d(TAG, "setAppConfigBean: 调用 | config=" + config);
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, "setAppConfigBean: 配置Bean为空,同步失败");
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
// 配置参数同步+范围校验
|
||||
isEnableChargeReminder = config.isEnableChargeReminder();
|
||||
isEnableUsageReminder = config.isEnableUsageReminder();
|
||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
|
||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
|
||||
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
||||
int currentBattery = config.getCurrentBatteryValue();
|
||||
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
|
||||
quantityOfElectricity = (config.getCurrentBatteryValue() >= 0 && config.getCurrentBatteryValue() <= 100)
|
||||
? config.getCurrentBatteryValue() : INVALID_BATTERY_VALUE;
|
||||
isCharging = config.isCharging();
|
||||
isReminding = isEnableChargeReminder || isEnableUsageReminder;
|
||||
|
||||
@@ -410,29 +336,39 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断线程是否处于运行状态
|
||||
*/
|
||||
private boolean isRunning() {
|
||||
boolean running = !isExist && isThreadStarted && isAlive();
|
||||
LogUtils.d(TAG, "isRunning: 线程运行状态=" + running + " | isExist=" + isExist + " | isThreadStarted=" + isThreadStarted + " | isAlive=" + isAlive());
|
||||
return running;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放线程所有资源(内部方法)
|
||||
* 释放线程资源(内部方法,防内存泄漏)
|
||||
*/
|
||||
private void releaseResourcesInternal() {
|
||||
LogUtils.d(TAG, "releaseResourcesInternal: 开始释放线程资源");
|
||||
LogUtils.d(TAG, "releaseResourcesInternal: 释放线程资源");
|
||||
mContext = null;
|
||||
if (mwrControlCenterServiceHandler != null) {
|
||||
mwrControlCenterServiceHandler.clear();
|
||||
mwrControlCenterServiceHandler = null;
|
||||
}
|
||||
cleanThreadStateInternal();
|
||||
LogUtils.d(TAG, "releaseResourcesInternal: 线程资源释放完成");
|
||||
}
|
||||
|
||||
// ================================== 调试辅助(toString 私有化,避免对外暴露状态)=================================
|
||||
/**
|
||||
* 判断线程是否处于运行状态
|
||||
* @return true: 运行中;false: 已停止
|
||||
*/
|
||||
private boolean isRunning() {
|
||||
boolean running = !isExist && isAlive();
|
||||
LogUtils.d(TAG, "isRunning: 线程运行状态=" + running + " | isExist=" + isExist + " | isAlive=" + isAlive());
|
||||
return running;
|
||||
}
|
||||
|
||||
// ================================== Getter/Setter(按需开放)=================================
|
||||
public void setIsExist(boolean isExist) {
|
||||
LogUtils.d(TAG, "setIsExist: 调用 | isExist=" + isExist);
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
return isExist;
|
||||
}
|
||||
|
||||
// ================================== 调试辅助方法=================================
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemindThread{" +
|
||||
|
||||
Reference in New Issue
Block a user