服务自启配置持久化

This commit is contained in:
2025-12-17 16:24:49 +08:00
parent 683dc6791e
commit 5cf47172f4
5 changed files with 770 additions and 400 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Dec 17 07:16:02 GMT 2025 #Wed Dec 17 08:23:18 GMT 2025
stageCount=10 stageCount=10
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.9 publishVersion=15.14.9
buildCount=11 buildCount=16
baseBetaVersion=15.14.10 baseBetaVersion=15.14.10

View File

@@ -10,7 +10,7 @@ import cc.winboll.studio.powerbell.models.NotificationMessage;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:41 * @Date 2025/12/17 13:41
* @Describe 服务通信Handler弱引用持有服务避免内存泄漏适配Java7+API30统一处理服务消息 * @Describe 服务通信Handler弱引用持有服务避免内存泄漏通知格式优化为 (+/-)(当前电量)(充电状态)
*/ */
public class ControlCenterServiceHandler extends Handler { public class ControlCenterServiceHandler extends Handler {
// ================================== 静态常量(置顶统一管理,清晰区分消息类型)================================= // ================================== 静态常量(置顶统一管理,清晰区分消息类型)=================================
@@ -26,11 +26,15 @@ public class ControlCenterServiceHandler extends Handler {
this.mwrControlCenterService = new WeakReference<>(service); this.mwrControlCenterService = new WeakReference<>(service);
} }
// ================================== 核心消息处理重写handleMessage按类型分发================================= // ================================== 核心消息处理重写handleMessage解析多参数消息=================================
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
super.handleMessage(msg); super.handleMessage(msg);
LogUtils.d(TAG, "接收消息what" + msg.what + "obj" + (msg.obj != null ? msg.obj : "null")); // 解析线程传递的完整数据obj=提醒类型(+/-)arg1=当前电量arg2=充电状态(1=充电中0=未充电)
String remindType = (msg.obj != null) ? (String) msg.obj : "";
int currentBattery = msg.arg1;
boolean isCharging = msg.arg2 == 1;
LogUtils.d(TAG, "接收消息what" + msg.what + ",类型:" + remindType + ",电量:" + currentBattery + ",充电状态:" + isCharging);
// 弱引用获取服务,避免持有强引用导致内存泄漏 // 弱引用获取服务,避免持有强引用导致内存泄漏
ControlCenterService service = mwrControlCenterService.get(); ControlCenterService service = mwrControlCenterService.get();
@@ -42,7 +46,7 @@ public class ControlCenterServiceHandler extends Handler {
// 按消息类型分发处理,避免逻辑冗余 // 按消息类型分发处理,避免逻辑冗余
switch (msg.what) { switch (msg.what) {
case MSG_REMIND_TEXT: case MSG_REMIND_TEXT:
handleRemindMessage(service, (String) msg.obj); handleRemindMessage(service, remindType, currentBattery, isCharging);
break; break;
default: default:
LogUtils.w(TAG, "未知消息类型what" + msg.what); LogUtils.w(TAG, "未知消息类型what" + msg.what);
@@ -50,41 +54,51 @@ public class ControlCenterServiceHandler extends Handler {
} }
} }
// ================================== 业务辅助方法(单独处理提醒消息,职责单一================================= // ================================== 业务辅助方法(重构通知内容,格式:(+/-)(当前电量)(充电状态)=================================
/** /**
* 处理电量提醒消息,构建通知模型并调用工具类发送 * 处理电量提醒消息,构建带电量+充电状态的通知模型
* @param service 服务实例(非空,已前置校验) * @param service 服务实例(非空,已前置校验)
* @param content 消息内容+:充电提醒,-:耗电提醒) * @param remindType 提醒类型+:充电提醒,-:耗电提醒)
* @param currentBattery 当前电量0-100
* @param isCharging 充电状态true=充电中false=未充电)
*/ */
private void handleRemindMessage(ControlCenterService service, String content) { private void handleRemindMessage(ControlCenterService service, String remindType, int currentBattery, boolean isCharging) {
LogUtils.d(TAG, "开始处理提醒消息,内容:" + content); LogUtils.d(TAG, "开始处理提醒消息,类型:" + remindType + ",电量:" + currentBattery + ",充电状态:" + isCharging);
// 校验通知工具类,避免空指针 // 1. 前置校验通知工具类+提醒类型+电量有效性
if (service.getNotificationManager() == null) { if (service.getNotificationManager() == null) {
LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒"); LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒");
return; return;
} }
if (!"+".equals(remindType) && !"-".equals(remindType)) {
// 构建通知消息模型,区分充电/耗电场景 LogUtils.w(TAG, "无效提醒类型,跳过发送:" + remindType);
NotificationMessage remindMsg = new NotificationMessage(); return;
if ("+".equals(content)) { }
remindMsg.setTitle("充电提醒"); if (currentBattery < 0 || currentBattery > 100) {
remindMsg.setContent("电池电量已达标,建议及时断电,保护电池寿命~"); LogUtils.w(TAG, "无效当前电量,跳过发送:" + currentBattery);
remindMsg.setRemindMSG("charge_remind");
LogUtils.d(TAG, "构建充电提醒通知标识charge_remind");
} else if ("-".equals(content)) {
remindMsg.setTitle("耗电提醒");
remindMsg.setContent("电池电量偏低,建议及时充电,避免设备关机~");
remindMsg.setRemindMSG("usage_remind");
LogUtils.d(TAG, "构建耗电提醒通知标识usage_remind");
} else {
LogUtils.w(TAG, "无效提醒消息内容,跳过发送:" + content);
return; return;
} }
// 调用服务工具类发送通知,复用现有逻辑 // 2. 构建通知模型,按格式拼接内容(核心优化)
NotificationMessage remindMsg = new NotificationMessage();
String chargeStateDesc = isCharging ? "充电中" : "未充电"; // 充电状态文字描述
if ("+".equals(remindType)) {
// 充电提醒:格式 (+)(当前电量)(充电状态)
remindMsg.setTitle("充电提醒");
remindMsg.setContent("(+) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已达标建议及时断电,保护电池寿命~");
remindMsg.setRemindMSG("charge_remind");
LogUtils.d(TAG, "构建充电提醒通知,内容:" + remindMsg.getContent());
} else if ("-".equals(remindType)) {
// 耗电提醒:格式 (-)(当前电量)(充电状态)
remindMsg.setTitle("耗电提醒");
remindMsg.setContent("(-) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已偏低建议及时充电,避免设备关机~");
remindMsg.setRemindMSG("usage_remind");
LogUtils.d(TAG, "构建耗电提醒通知,内容:" + remindMsg.getContent());
}
// 3. 调用服务工具类发送通知,复用现有逻辑
service.getNotificationManager().showRemindNotification(service, remindMsg); service.getNotificationManager().showRemindNotification(service, remindMsg);
LogUtils.d(TAG, "提醒通知发送完成,标题:" + remindMsg.getTitle()); LogUtils.d(TAG, "提醒通知发送完成,标题:" + remindMsg.getTitle() + ",完整内容:" + remindMsg.getContent());
} }
} }

View File

@@ -1,99 +1,142 @@
package cc.winboll.studio.powerbell.models; package cc.winboll.studio.powerbell.models;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/18 07:06:07
* @Describe 服务控制参数
*/
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
// 核心修正:实现 Parcelable + Serializable 接口(适配持久化+Intent传递API30 必备) import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 15:55
* @Describe 服务控制参数模型管理服务启用状态支持序列化、Parcel传递、JSON解析
*/
public class ControlCenterServiceBean extends BaseBean implements Parcelable, Serializable { public class ControlCenterServiceBean extends BaseBean implements Parcelable, Serializable {
// ================================== 静态常量(置顶统一管理,避免魔法值)=================================
private static final long serialVersionUID = 1L; // Serializable 必备,保障反序列化兼容
private static final String TAG = "ControlCenterServiceBean";
// JSON 字段常量,避免硬编码,减少拼写错误
private static final String JSON_FIELD_IS_ENABLE_SERVICE = "isEnableService";
// 序列化版本号Serializable 必备,避免反序列化崩溃) // ================================== 核心成员变量(私有封装,规范命名)=================================
private static final long serialVersionUID = 1L; private boolean isEnableService = false; // 服务启用状态true=启用false=禁用
public static final String TAG = "ControlCenterServiceBean"; // ================================== Parcelable 静态创建器(必须 public static final适配 API30 传递)=================================
boolean isEnableService = false;
public ControlCenterServiceBean() {
this.isEnableService = false;
}
public ControlCenterServiceBean(boolean isEnableService) {
this.isEnableService = isEnableService;
}
public void setIsEnableService(boolean isEnableService) {
this.isEnableService = isEnableService;
}
public boolean isEnableService() {
return isEnableService;
}
@Override
public String getName() {
return ControlCenterServiceBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
ControlCenterServiceBean bean = this;
jsonWriter.name("isEnableService").value(bean.isEnableService());
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
ControlCenterServiceBean bean = new ControlCenterServiceBean();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals("isEnableService")) {
bean.setIsEnableService(jsonReader.nextBoolean());
} else {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return bean;
}
// ======================== 补全Parcelable 接口实现API30 持久化/Intent传递必备========================
@Override
public int describeContents() {
return 0; // 无特殊内容描述返回0即可
}
// 序列化:将对象属性写入 Parcel
@Override
public void writeToParcel(Parcel dest, int flags) {
// boolean 类型用 byte 存储Parcel 无直接 writeBoolean 方法Java7 适配)
dest.writeByte((byte) (isEnableService ? 1 : 0));
}
// 反序列化:从 Parcel 读取属性,创建对象(必须是 public static final 修饰)
public static final Parcelable.Creator<ControlCenterServiceBean> CREATOR = new Parcelable.Creator<ControlCenterServiceBean>() { public static final Parcelable.Creator<ControlCenterServiceBean> CREATOR = new Parcelable.Creator<ControlCenterServiceBean>() {
@Override @Override
public ControlCenterServiceBean createFromParcel(Parcel source) { public ControlCenterServiceBean createFromParcel(Parcel source) {
// 从 Parcel 读取 byte转为 boolean LogUtils.d(TAG, "Parcelable createFromParcel: 从Parcel反序列化对象");
// Java7 + API30 适配Parcel 无直接 writeBoolean用 byte 存储/读取
boolean isEnable = source.readByte() != 0; boolean isEnable = source.readByte() != 0;
return new ControlCenterServiceBean(isEnable); ControlCenterServiceBean bean = new ControlCenterServiceBean(isEnable);
LogUtils.d(TAG, "Parcelable createFromParcel: 反序列化完成isEnableService=" + isEnable);
return bean;
} }
@Override @Override
public ControlCenterServiceBean[] newArray(int size) { public ControlCenterServiceBean[] newArray(int size) {
LogUtils.d(TAG, "Parcelable newArray: 创建数组,长度=" + size);
return new ControlCenterServiceBean[size]; return new ControlCenterServiceBean[size];
} }
}; };
// ================================== 构造方法(无参+有参,满足不同初始化场景)=================================
/**
* 无参构造JSON解析、反射创建必备
*/
public ControlCenterServiceBean() {
this.isEnableService = false;
LogUtils.d(TAG, "无参构造初始化服务状态为禁用false");
}
/**
* 有参构造(指定服务启用状态)
* @param isEnableService 服务启用状态
*/
public ControlCenterServiceBean(boolean isEnableService) {
this.isEnableService = isEnableService;
LogUtils.d(TAG, "有参构造初始化服务状态isEnableService=" + isEnableService);
}
// ================================== Getter/Setter 方法(封装成员变量,控制访问)=================================
public boolean isEnableService() {
LogUtils.d(TAG, "get isEnableService: 当前状态=" + isEnableService);
return isEnableService;
}
public void setIsEnableService(boolean isEnableService) {
LogUtils.d(TAG, "set isEnableService: 旧状态=" + this.isEnableService + ",新状态=" + isEnableService);
this.isEnableService = isEnableService;
}
// ================================== 父类 BaseBean 方法重写(核心业务逻辑)=================================
@Override
public String getName() {
String className = ControlCenterServiceBean.class.getName();
LogUtils.d(TAG, "getName: 返回类名=" + className);
return className;
}
/**
* 序列化对象到 JSON适配数据持久化/网络传输)
*/
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
LogUtils.d(TAG, "writeThisToJsonWriter: 开始将对象序列化到JSON");
super.writeThisToJsonWriter(jsonWriter);
// 写入服务启用状态字段
jsonWriter.name(JSON_FIELD_IS_ENABLE_SERVICE).value(this.isEnableService);
LogUtils.d(TAG, "writeThisToJsonWriter: JSON序列化完成字段=" + JSON_FIELD_IS_ENABLE_SERVICE + ",值=" + this.isEnableService);
}
/**
* 从 JSON 反序列化创建对象(适配数据恢复)
*/
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
LogUtils.d(TAG, "readBeanFromJsonReader: 开始从JSON反序列化对象");
ControlCenterServiceBean bean = new ControlCenterServiceBean();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String fieldName = jsonReader.nextName();
if (JSON_FIELD_IS_ENABLE_SERVICE.equals(fieldName)) {
// 读取并设置服务启用状态
boolean isEnable = jsonReader.nextBoolean();
bean.setIsEnableService(isEnable);
LogUtils.d(TAG, "readBeanFromJsonReader: 读取JSON字段" + fieldName + "=" + isEnable);
} else {
// 跳过未知字段,避免解析异常
jsonReader.skipValue();
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未知JSON字段=" + fieldName);
}
}
jsonReader.endObject();
LogUtils.d(TAG, "readBeanFromJsonReader: JSON反序列化完成");
return bean;
}
// ================================== Parcelable 接口方法实现(适配 Intent 组件间传递)=================================
@Override
public int describeContents() {
// 无特殊内容如文件描述符返回0即可API30 标准实现)
LogUtils.d(TAG, "describeContents: 返回内容描述符=0");
return 0;
}
/**
* 序列化对象到 ParcelIntent 传递必备Java7 适配)
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
LogUtils.d(TAG, "writeToParcel: 开始将对象序列化到Parcelflags=" + flags);
// Java7 + API30 适配Parcel 无 writeBoolean 方法,用 byte 存储1=true0=false
dest.writeByte((byte) (this.isEnableService ? 1 : 0));
LogUtils.d(TAG, "writeToParcel: Parcel序列化完成isEnableService=" + this.isEnableService + "存储为byte=" + (this.isEnableService ? 1 : 0) + "");
}
} }

View File

@@ -10,212 +10,218 @@ import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import java.io.Serializable;
import java.util.List;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler; import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.models.AppConfigBean; import cc.winboll.studio.powerbell.models.AppConfigBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.models.NotificationMessage; import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.threads.RemindThread; import cc.winboll.studio.powerbell.threads.RemindThread;
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils; import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import java.io.Serializable;
import java.util.List;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 15:48
* @Describe 电池提醒核心服务:通过本地持久化 ControlCenterServiceBean 控制自启动统一管理线程、通知、配置适配Java7+API30
*/
public class ControlCenterService extends Service { public class ControlCenterService extends Service {
// ================================== 静态常量(置顶统一管理,避免魔法值)=================================
private static final String TAG = "ControlCenterService"; private static final String TAG = "ControlCenterService";
// Intent指令常量(完整包名前缀,避免冲突) // 服务指令常量(包名前缀,防止冲突)
public static final String ACTION_RESTART_REMIND_THREAD = "cc.winboll.studio.powerbell.action.RESTART_REMIND_THREAD"; 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"; public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
// 核心成员变量 // ================================== 核心成员变量(按依赖优先级排序,私有封装)=================================
private ControlCenterServiceHandler mServiceHandler; // 服务控制核心本地持久化管理替代Intent传递
private RemindThread mRemindThread; private ControlCenterServiceBean mServiceControlBean;
private NotificationManagerUtils mNotificationManager; // 业务核心组件
private NotificationMessage mForegroundNotifyMsg; private ControlCenterServiceHandler mServiceHandler; // 服务通信Handler
private AppConfigBean mCurrentConfigBean; private RemindThread mRemindThread; // 电量提醒线程
private boolean isServiceRunning = false; private NotificationManagerUtils mNotificationManager; // 通知管理工具类
private boolean mIsDestroyed = false; // 服务销毁状态标记供Receiver判断 private AppConfigBean mCurrentConfigBean; // 当前应用配置
private final Object mServiceLock = new Object(); // 并发锁(避免多线程冲突) // 前台服务相关
private NotificationMessage mForegroundNotifyMsg; // 前台保活通知模型
// 状态标记(并发安全)
private boolean isServiceRunning = false; // 服务运行状态
private boolean mIsDestroyed = false; // 服务销毁标记
private final Object mServiceLock = new Object(); // 全局并发锁
// ================================== 服务生命周期方法onCreate→onStartCommand→onDestroy=================================
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
LogUtils.d(TAG, "onCreate: 服务创建,初始化核心组件"); LogUtils.d(TAG, "onCreate: 服务开始创建");
synchronized (mServiceLock) {
isServiceRunning = true; isServiceRunning = true;
mIsDestroyed = false; mIsDestroyed = false;
initNotificationManager(); // 初始化服务控制配置:优先读取本地持久化配置,无则创建默认禁用配置
startForegroundNotifyImmediately(); mServiceControlBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
loadDefaultConfig(); if (mServiceControlBean == null) {
initServiceBusinessLogic(); mServiceControlBean = new ControlCenterServiceBean(false);
LogUtils.d(TAG, "onCreate: 服务初始化完成"); ControlCenterServiceBean.saveBean(this, mServiceControlBean); // 持久化默认配置
LogUtils.d(TAG, "onCreate: 本地无控制配置,创建默认禁用配置并持久化");
} else {
LogUtils.d(TAG, "onCreate: 从本地读取服务控制配置,启用状态=" + mServiceControlBean.isEnableService());
}
}
LogUtils.d(TAG, "onCreate: 服务创建完成,当前服务控制状态:" + (mServiceControlBean.isEnableService() ? "启用" : "禁用"));
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand: 触发服务启动命令flags=" + flags); LogUtils.d(TAG, "onStartCommand: 服务启动指令触发flags=" + flags);
handleExternalCommand(intent); // 第一步:读取本地最新控制配置(优先级最高,实时同步用户设置)
loadLatestServiceControlConfig();
// 重新绑定前台服务避免API30+状态丢失(加判空容错) // 第二步:根据控制状态,分支执行逻辑
if (mNotificationManager != null && mNotificationManager.getForegroundServiceNotify() != null) {
try {
startForeground(NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE,
mNotificationManager.getForegroundServiceNotify());
LogUtils.d(TAG, "onStartCommand: 重新绑定前台通知保活");
} catch (Exception e) {
LogUtils.e(TAG, "onStartCommand: 重新绑定前台通知异常", e);
}
}
return START_STICKY; // 服务回收后自动重启
}
// 处理外部指令(重启线程)- 加锁避免并发调用
private void handleExternalCommand(Intent intent) {
LogUtils.d(TAG, "handleExternalCommand: 处理外部指令");
if (intent == null) {
LogUtils.e(TAG, "handleExternalCommand: Intent为空跳过");
return;
}
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
LogUtils.e(TAG, "handleExternalCommand: 指令Action为空跳过");
return;
}
synchronized (mServiceLock) { // 关键:加锁,防止并发触发重启导致线程冲突
if (ACTION_RESTART_REMIND_THREAD.equals(action)) {
AppConfigBean newConfig = (AppConfigBean) intent.getSerializableExtra(EXTRA_APP_CONFIG_BEAN);
if (newConfig != null) {
mCurrentConfigBean = newConfig;
LogUtils.d(TAG, "handleExternalCommand: 收到重启指令,更新配置");
restartRemindThreadSafely();
} else {
LogUtils.e(TAG, "handleExternalCommand: 新配置为空,重启失败");
}
}
}
}
// 安全重启提醒线程 - 核心修复:彻底销毁旧线程,确保新线程是全新实例
public void restartRemindThreadSafely() {
LogUtils.d(TAG, "restartRemindThreadSafely: 重启提醒线程");
synchronized (mServiceLock) { // 加锁,避免与服务销毁/其他重启操作冲突
// 1. 先彻底停止旧线程(调用独立封装的安全停止方法)
stopRemindThreadSafely();
// 2. 校验服务状态,避免服务已停止时启动线程
if (!isServiceRunning || mServiceHandler == null || mIsDestroyed) {
LogUtils.e(TAG, "restartRemindThreadSafely: 服务未运行/已销毁/Handler为空启动失败");
return;
}
// 3. 强制销毁RemindThread单例关键避免复用旧线程对象
RemindThread.destroyInstance(); // 必须调用确保getInstance返回新实例
// 4. 创建新线程实例此时是全新Thread对象未启动
mRemindThread = RemindThread.getInstance(this, mServiceHandler);
syncConfigToRemindThread();
// 5. 双重校验线程状态杜绝重复start()
if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
try {
mRemindThread.start(); // 修复崩溃核心仅对全新线程调用start()
LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功ID=" + mRemindThread.getId());
} catch (IllegalThreadStateException e) {
// 兜底捕获:即使校验失败,也避免崩溃,打印详细日志
LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常(致命错误)", e);
mRemindThread = null; // 启动失败,置空避免后续错误
} catch (Exception e) {
LogUtils.e(TAG, "restartRemindThreadSafely: 启动新线程异常", e);
mRemindThread = null;
}
} else {
LogUtils.w(TAG, "restartRemindThreadSafely: 线程已启动/实例异常,无需重复操作");
mRemindThread = null;
}
}
}
// 安全停止提醒线程 - 优化:确保线程彻底终止,无残留
private void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely: 安全停止提醒线程");
if (mRemindThread == null) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程实例为空,跳过");
return;
}
try {
// 1. 先通过线程内部方法标记停止依赖RemindThread的stopThread实现
if (mRemindThread.isThreadStarted() || mRemindThread.isAlive()) {
mRemindThread.setIsReminding(false); // 关闭提醒功能
mRemindThread.stopThread(); // 触发线程安全停止(置位退出标记+中断休眠)
LogUtils.d(TAG, "stopRemindThreadSafely: 触发线程内部停止逻辑");
// 2. 等待线程终止最多1秒避免阻塞服务超时强制置空
long waitStartTime = System.currentTimeMillis();
while (mRemindThread.isAlive()) {
if (System.currentTimeMillis() - waitStartTime > 1000) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程停止超时,强制终止处理");
mRemindThread.interrupt(); // 强制中断,加速退出
break;
}
Thread.yield(); // 让出CPU优先执行线程退出逻辑
}
}
} catch (Exception e) {
LogUtils.e(TAG, "stopRemindThreadSafely: 线程停止异常", e);
} finally {
// 3. 彻底释放:置空实例+销毁单例,杜绝复用
mRemindThread = null;
RemindThread.destroyInstance(); // 关键销毁单例避免getInstance复用旧对象
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止完成,资源已释放");
}
}
// 同步配置到提醒线程 - 加锁避免并发修改
private void syncConfigToRemindThread() {
LogUtils.d(TAG, "syncConfigToRemindThread: 同步配置到线程");
synchronized (mServiceLock) { synchronized (mServiceLock) {
if (mRemindThread == null || mCurrentConfigBean == null) { if (mServiceControlBean.isEnableService()) {
LogUtils.e(TAG, "syncConfigToRemindThread: 线程/配置为空,同步失败"); LogUtils.d(TAG, "onStartCommand: 服务已启用,执行核心逻辑");
// 启用状态:处理指令+绑定前台通知+启动业务返回START_STICKY回收后重启
handleExternalCommand(intent);
rebindForegroundNotify();
initServiceBusinessIfNeed(); // 按需初始化业务(避免重复初始化)
LogUtils.d(TAG, "onStartCommand: 核心逻辑执行完成返回START_STICKY");
return START_STICKY;
} else {
LogUtils.d(TAG, "onStartCommand: 服务已禁用,不执行核心逻辑");
// 禁用状态:停止所有业务+释放资源,返回父类默认值(回收后不主动重启)
stopAllBusinessSafely();
LogUtils.d(TAG, "onStartCommand: 已停止所有业务返回父类默认onStartCommand结果");
return super.onStartCommand(intent, flags, startId);
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 服务开始销毁,释放所有资源");
synchronized (mServiceLock) {
isServiceRunning = false;
mIsDestroyed = true;
}
// 顺序释放资源前台服务→线程→Handler→通知→配置→控制Bean
stopForegroundService();
stopRemindThreadSafely();
destroyHandler();
releaseNotificationResource();
clearAllReferences();
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
}
@Override
public IBinder onBind(Intent intent) {
return null; // 无需绑定服务返回null
}
// ================================== 核心服务控制配置本地持久化读写替代Intent传递=================================
/**
* 读取本地最新服务控制配置(实时同步,确保与用户设置一致)
*/
private void loadLatestServiceControlConfig() {
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取本地最新服务控制配置");
synchronized (mServiceLock) {
ControlCenterServiceBean latestControlBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
if (latestControlBean != null) {
boolean oldState = mServiceControlBean.isEnableService();
boolean newState = latestControlBean.isEnableService();
mServiceControlBean = latestControlBean;
LogUtils.d(TAG, "loadLatestServiceControlConfig: 控制配置更新完成,旧状态=" + oldState + ",新状态=" + newState);
} else {
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无控制配置,沿用当前状态=" + mServiceControlBean.isEnableService());
}
}
LogUtils.d(TAG, "loadLatestServiceControlConfig: 控制配置读取完成,当前服务启用状态=" + mServiceControlBean.isEnableService());
}
/**
* 更新服务控制配置(本地持久化+内存同步,对外提供统一入口)
*/
private void updateAndSaveServiceControlConfig(ControlCenterServiceBean newControlBean) {
LogUtils.d(TAG, "updateAndSaveServiceControlConfig: 更新服务控制配置,新状态=" + newControlBean.isEnableService());
if (newControlBean == null) {
LogUtils.e(TAG, "updateAndSaveServiceControlConfig: 新控制配置为空,更新失败");
return; return;
} }
mRemindThread.setAppConfigBean(mCurrentConfigBean); // 同步完整配置
mRemindThread.setIsReminding(true); // 开启提醒功能 synchronized (mServiceLock) {
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步完成"); // 内存同步+本地持久化(原子操作,确保一致性)
mServiceControlBean = newControlBean;
ControlCenterServiceBean.saveBean(this, mServiceControlBean);
LogUtils.d(TAG, "updateAndSaveServiceControlConfig: 控制配置更新并持久化完成");
} }
} }
// 加载默认配置 - 优化:补全必要配置项,避免空指针 // ================================== 业务按需初始化/停止方法(适配启用/禁用状态切换)=================================
private void loadDefaultConfig() { /**
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置"); * 按需初始化核心业务(仅服务启用且未初始化时执行,避免重复创建)
mCurrentConfigBean = new AppConfigBean(); */
mCurrentConfigBean.setEnableChargeReminder(true); private void initServiceBusinessIfNeed() {
mCurrentConfigBean.setChargeReminderValue(80); LogUtils.d(TAG, "initServiceBusinessIfNeed: 按需初始化业务");
mCurrentConfigBean.setEnableUsageReminder(true); synchronized (mServiceLock) {
mCurrentConfigBean.setUsageReminderValue(20); // 校验:服务启用+未初始化+服务运行中
mCurrentConfigBean.setBatteryDetectInterval(1000); // 电池检测间隔1秒 if (!mServiceControlBean.isEnableService() || mServiceHandler != null || !isServiceRunning || mIsDestroyed) {
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成"); LogUtils.w(TAG, "initServiceBusinessIfNeed: 无需初始化业务(禁用/已初始化/服务未运行)");
return;
} }
// 初始化通知工具类 - 优化:移除无效调用,强化容错 // 初始化通知+配置+业务逻辑(完整启动核心流程)
initNotificationManager();
loadDefaultConfig();
initServiceBusinessLogic();
LogUtils.d(TAG, "initServiceBusinessIfNeed: 核心业务初始化完成");
}
}
/**
* 安全停止所有核心业务(服务禁用时执行,释放所有业务资源)
*/
private void stopAllBusinessSafely() {
LogUtils.d(TAG, "stopAllBusinessSafely: 停止所有核心业务");
synchronized (mServiceLock) {
// 停止线程+销毁Handler+释放通知+置空业务引用
stopRemindThreadSafely();
destroyHandler();
stopForegroundService();
releaseNotificationResource();
mCurrentConfigBean = null;
mForegroundNotifyMsg = null;
LogUtils.d(TAG, "stopAllBusinessSafely: 所有核心业务已停止");
}
}
// ================================== 核心业务初始化方法(按依赖顺序排列)=================================
/**
* 初始化通知管理工具类,构建前台保活通知模型
*/
private void initNotificationManager() { private void initNotificationManager() {
LogUtils.d(TAG, "initNotificationManager: 初始化通知工具类"); LogUtils.d(TAG, "initNotificationManager: 初始化通知工具类");
try { try {
if (mNotificationManager == null) {
mNotificationManager = new NotificationManagerUtils(this); mNotificationManager = new NotificationManagerUtils(this);
}
if (mForegroundNotifyMsg == null) {
mForegroundNotifyMsg = new NotificationMessage(); mForegroundNotifyMsg = new NotificationMessage();
mForegroundNotifyMsg.setTitle("电池提醒服务运行中"); mForegroundNotifyMsg.setTitle("电池提醒服务运行中");
mForegroundNotifyMsg.setContent("后台持续监测电池状态,确保提醒及时"); mForegroundNotifyMsg.setContent("后台持续监测电池状态,确保提醒及时");
mForegroundNotifyMsg.setRemindMSG("service_running"); mForegroundNotifyMsg.setRemindMSG("service_running");
// 移除无效调用getForegroundServiceNotify() 无需提前触发,启动时自动构建 // 启动前台保活通知
startForegroundNotifyImmediately();
}
LogUtils.d(TAG, "initNotificationManager: 通知工具类初始化完成");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "initNotificationManager: 初始化失败", e); LogUtils.e(TAG, "initNotificationManager: 初始化失败", e);
stopSelf(); // 通知初始化失败,直接停止服务,避免后续异常
} }
} }
// 立即启动前台服务通知 - 优化加try-catch避免启动失败崩溃 /**
* 立即启动前台保活通知API26+ 前台服务必需)
*/
private void startForegroundNotifyImmediately() { private void startForegroundNotifyImmediately() {
LogUtils.d(TAG, "startForegroundNotifyImmediately: 启动前台保活通知"); LogUtils.d(TAG, "startForegroundNotifyImmediately: 启动前台保活通知");
if (mNotificationManager == null || mForegroundNotifyMsg == null) { if (mNotificationManager == null || mForegroundNotifyMsg == null) {
LogUtils.e(TAG, "startForegroundNotifyImmediately: 依赖组件为空,启动失败"); LogUtils.e(TAG, "startForegroundNotifyImmediately: 通知工具类/模型为空,启动失败");
stopSelf();
return; return;
} }
@@ -224,20 +230,256 @@ public class ControlCenterService extends Service {
LogUtils.d(TAG, "startForegroundNotifyImmediately: 前台通知启动成功ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE); LogUtils.d(TAG, "startForegroundNotifyImmediately: 前台通知启动成功ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "startForegroundNotifyImmediately: 前台通知启动异常", e); LogUtils.e(TAG, "startForegroundNotifyImmediately: 前台通知启动异常", e);
stopSelf(); // 前台服务启动失败停止服务API26+前台服务必须正常启动)
} }
} }
// 初始化业务逻辑 - 优化:复用重启方法,统一线程启动逻辑 /**
* 重新绑定前台通知onStartCommand触发防止保活状态丢失
*/
private void rebindForegroundNotify() {
if (mNotificationManager == null || mNotificationManager.getForegroundServiceNotify() == null) {
LogUtils.w(TAG, "rebindForegroundNotify: 通知工具类/前台通知为空,跳过绑定");
return;
}
try {
startForeground(NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE, mNotificationManager.getForegroundServiceNotify());
LogUtils.d(TAG, "rebindForegroundNotify: 前台通知重新绑定成功");
} catch (Exception e) {
LogUtils.e(TAG, "rebindForegroundNotify: 重新绑定前台通知异常", e);
}
}
/**
* 加载默认应用配置(服务启动时兜底)
*/
private void loadDefaultConfig() {
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置");
if (mCurrentConfigBean == null) {
mCurrentConfigBean = new AppConfigBean();
mCurrentConfigBean.setEnableChargeReminder(true);
mCurrentConfigBean.setChargeReminderValue(80);
mCurrentConfigBean.setEnableUsageReminder(true);
mCurrentConfigBean.setUsageReminderValue(20);
mCurrentConfigBean.setBatteryDetectInterval(1000);
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成充电阈值80%耗电阈值20%");
} else {
LogUtils.d(TAG, "loadDefaultConfig: 配置已存在,无需重复加载");
}
}
/**
* 初始化业务核心逻辑Handler+提醒线程)
*/
private void initServiceBusinessLogic() { private void initServiceBusinessLogic() {
LogUtils.d(TAG, "initServiceBusinessLogic: 初始化业务组件"); LogUtils.d(TAG, "initServiceBusinessLogic: 初始化业务逻辑");
if (mServiceHandler == null) {
mServiceHandler = new ControlCenterServiceHandler(this); mServiceHandler = new ControlCenterServiceHandler(this);
// 关键复用restartRemindThreadSafely避免重复写启动逻辑 }
// 复用线程重启方法,统一启动逻辑
restartRemindThreadSafely(); restartRemindThreadSafely();
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化完成"); LogUtils.d(TAG, "initServiceBusinessLogic: 业务逻辑初始化完成");
} }
// 启动服务(静态入口)- 优化:强化包名绑定,避免隐式启动失败 // ================================== 线程管理方法(安全启动/停止/重启,保障并发安全)=================================
/**
* 安全重启提醒线程(彻底销毁旧线程,创建全新实例,避免重复启动)
*/
public void restartRemindThreadSafely() {
LogUtils.d(TAG, "restartRemindThreadSafely: 开始重启提醒线程");
synchronized (mServiceLock) {
// 服务禁用/已销毁,直接返回
if (!isServiceRunning || mIsDestroyed || !mServiceControlBean.isEnableService()) {
LogUtils.e(TAG, "restartRemindThreadSafely: 服务未运行/已销毁/已禁用,启动失败");
return;
}
// 先停止旧线程
stopRemindThreadSafely();
// 校验Handler避免无效启动
if (mServiceHandler == null) {
LogUtils.e(TAG, "restartRemindThreadSafely: Handler为空启动失败");
return;
}
// 销毁旧单例,创建新线程实例
RemindThread.destroyInstance();
mRemindThread = RemindThread.getInstance(this, mServiceHandler);
// 同步配置并开启提醒
syncConfigToRemindThread();
// 双重校验,避免线程重复启动
if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
try {
mRemindThread.start();
LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功ID=" + mRemindThread.getId());
} catch (IllegalThreadStateException e) {
LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常", e);
mRemindThread = null;
} catch (Exception e) {
LogUtils.e(TAG, "restartRemindThreadSafely: 启动线程异常", e);
mRemindThread = null;
}
} else {
LogUtils.w(TAG, "restartRemindThreadSafely: 线程已启动/实例异常,跳过启动");
mRemindThread = null;
}
}
LogUtils.d(TAG, "restartRemindThreadSafely: 线程重启流程结束");
}
/**
* 安全停止提醒线程(中断休眠+等待终止+释放资源,无残留)
*/
private void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely: 开始停止提醒线程");
if (mRemindThread == null) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程实例为空,跳过停止");
return;
}
try {
// 触发线程内部停止逻辑
if (mRemindThread.isThreadStarted() || mRemindThread.isAlive()) {
mRemindThread.setIsReminding(false);
mRemindThread.stopThread();
LogUtils.d(TAG, "stopRemindThreadSafely: 触发线程内部停止");
// 等待线程终止超时1秒避免阻塞服务
long waitStartTime = System.currentTimeMillis();
while (mRemindThread.isAlive()) {
if (System.currentTimeMillis() - waitStartTime > 1000) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程停止超时,强制中断");
mRemindThread.interrupt();
break;
}
Thread.yield();
}
}
} catch (Exception e) {
LogUtils.e(TAG, "stopRemindThreadSafely: 停止线程异常", e);
} finally {
// 彻底释放资源
mRemindThread = null;
RemindThread.destroyInstance();
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止完成,资源已释放");
}
}
/**
* 同步配置到提醒线程(原子操作,避免并发修改)
*/
private void syncConfigToRemindThread() {
LogUtils.d(TAG, "syncConfigToRemindThread: 同步配置到线程");
synchronized (mServiceLock) {
if (mRemindThread == null || mCurrentConfigBean == null) {
LogUtils.e(TAG, "syncConfigToRemindThread: 线程/配置为空,同步失败");
return;
}
mRemindThread.setAppConfigBean(mCurrentConfigBean);
mRemindThread.setIsReminding(true);
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步完成");
}
}
// ================================== 外部指令处理方法(接收重启/更新配置指令移除控制Bean传递=================================
/**
* 处理外部发送的服务指令(如重启线程、更新配置)
*/
private void handleExternalCommand(Intent intent) {
LogUtils.d(TAG, "handleExternalCommand: 开始处理外部指令");
if (intent == null) {
LogUtils.e(TAG, "handleExternalCommand: Intent为空跳过处理");
return;
}
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
LogUtils.e(TAG, "handleExternalCommand: 指令Action为空跳过处理");
return;
}
// 处理线程重启指令(仅同步业务配置,服务控制配置从本地读取)
if (ACTION_RESTART_REMIND_THREAD.equals(action)) {
// 读取本地最新控制配置,确保状态同步
loadLatestServiceControlConfig();
// 仅启用状态下,更新业务配置并重启线程
synchronized (mServiceLock) {
if (mServiceControlBean.isEnableService()) {
AppConfigBean newConfig = (AppConfigBean) intent.getSerializableExtra(EXTRA_APP_CONFIG_BEAN);
if (newConfig != null) {
mCurrentConfigBean = newConfig;
LogUtils.d(TAG, "handleExternalCommand: 收到线程重启指令,已更新业务配置");
restartRemindThreadSafely();
} else {
LogUtils.e(TAG, "handleExternalCommand: 新业务配置为空,重启线程失败");
}
} else {
LogUtils.w(TAG, "handleExternalCommand: 服务已禁用,忽略线程重启指令");
}
}
}
LogUtils.d(TAG, "handleExternalCommand: 外部指令处理完成");
}
// ================================== 服务资源释放方法(顺序化释放,防内存泄漏)=================================
/**
* 停止前台服务(取消通知+移除前台状态)
*/
private void stopForegroundService() {
LogUtils.d(TAG, "stopForegroundService: 停止前台服务");
// 取消前台通知
if (mNotificationManager != null) {
mNotificationManager.cancelForegroundServiceNotify();
}
// 移除前台服务状态
try {
stopForeground(STOP_FOREGROUND_REMOVE);
LogUtils.d(TAG, "stopForegroundService: 前台服务状态移除成功");
} catch (Exception e) {
LogUtils.e(TAG, "stopForegroundService: 移除前台状态异常", e);
}
}
/**
* 销毁Handler移除所有任务避免内存泄漏
*/
private void destroyHandler() {
LogUtils.d(TAG, "destroyHandler: 销毁服务Handler");
if (mServiceHandler != null) {
mServiceHandler.removeCallbacksAndMessages(null);
mServiceHandler = null;
LogUtils.d(TAG, "destroyHandler: Handler销毁完成");
}
}
/**
* 释放通知资源(调用工具类释放方法)
*/
private void releaseNotificationResource() {
LogUtils.d(TAG, "releaseNotificationResource: 释放通知资源");
if (mNotificationManager != null) {
mNotificationManager.release();
mNotificationManager = null;
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放完成");
}
}
/**
* 置空所有引用帮助GC回收
*/
private void clearAllReferences() {
mForegroundNotifyMsg = null;
mCurrentConfigBean = null;
mServiceControlBean = null;
LogUtils.d(TAG, "clearAllReferences: 所有引用已置空");
}
// ================================== 静态工具方法(服务启动/停止/状态判断/电池优化简化控制Bean传递=================================
/**
* 启动服务静态入口从本地读取控制配置显式绑定包名适配API30+
*/
public static void startControlCenterService(Context context) { public static void startControlCenterService(Context context) {
LogUtils.d(TAG, "startControlCenterService: 启动服务入口"); LogUtils.d(TAG, "startControlCenterService: 启动服务入口");
if (context == null) { if (context == null) {
@@ -245,12 +487,15 @@ public class ControlCenterService extends Service {
return; return;
} }
if (isServiceRunning(context, ControlCenterService.class)) { if (isServiceRunning(context, ControlCenterService.class)) {
LogUtils.d(TAG, "startControlCenterService: 服务已运行,跳过启动"); LogUtils.d(TAG, "startControlCenterService: 服务已运行,同步本地控制配置");
// 服务已运行触发onStartCommand同步最新配置
sendSyncConfigCommand(context);
return; return;
} }
Intent intent = new Intent(context, ControlCenterService.class); Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName()); // 显式绑定包名,避免组件冲突 intent.setPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); // 兼容服务被停止的场景 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
try { try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent); context.startForegroundService(intent);
@@ -263,7 +508,9 @@ public class ControlCenterService extends Service {
} }
} }
// 停止服务(静态入口)- 优化:强化包名绑定 /**
* 停止服务(静态入口,显式绑定包名)
*/
public static void stopControlCenterService(Context context) { public static void stopControlCenterService(Context context) {
LogUtils.d(TAG, "stopControlCenterService: 停止服务入口"); LogUtils.d(TAG, "stopControlCenterService: 停止服务入口");
if (context == null) { if (context == null) {
@@ -274,52 +521,121 @@ public class ControlCenterService extends Service {
LogUtils.d(TAG, "stopControlCenterService: 服务未运行,跳过停止"); LogUtils.d(TAG, "stopControlCenterService: 服务未运行,跳过停止");
return; return;
} }
Intent intent = new Intent(context, ControlCenterService.class); Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName()); intent.setPackage(context.getPackageName());
context.stopService(intent); context.stopService(intent);
LogUtils.d(TAG, "stopControlCenterService: 服务停止指令发送成功"); LogUtils.d(TAG, "stopControlCenterService: 服务停止指令发送成功");
} }
// 判断服务是否运行 - 优化适配API30+ ActivityManager限制 /**
private static boolean isServiceRunning(Context context, Class<?> serviceClass) { * 新增:更新服务控制配置(本地持久化,动态切换服务启用/禁用状态)
if (context == null || serviceClass == null) return false; */
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); public static void updateServiceControlConfig(Context context, ControlCenterServiceBean controlBean) {
if (am == null) return false; LogUtils.d(TAG, "updateServiceControlConfig: 更新服务控制配置,新状态=" + controlBean.isEnableService());
if (context == null || controlBean == null) {
LogUtils.e(TAG, "updateServiceControlConfig: Context/控制配置为空,更新失败");
return;
}
// API30+ 限制getRunningServices返回空改用getRunningTasks兼容或用JobScheduler此处先兼容 // 第一步:本地持久化配置
ControlCenterServiceBean.saveBean(context, controlBean);
LogUtils.d(TAG, "updateServiceControlConfig: 控制配置已持久化");
// 第二步:若服务已运行,触发同步(让服务立即生效)
if (isServiceRunning(context, ControlCenterService.class)) {
sendSyncConfigCommand(context);
LogUtils.d(TAG, "updateServiceControlConfig: 服务已运行,已触发配置同步");
} else {
// 服务未运行,按需启动服务(根据新配置决定是否启用业务)
startControlCenterService(context);
LogUtils.d(TAG, "updateServiceControlConfig: 服务未运行,已启动服务并加载新配置");
}
}
/**
* 新增:发送配置同步指令(触发服务读取本地最新配置,立即生效)
*/
private static void sendSyncConfigCommand(Context context) {
Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
} catch (Exception e) {
LogUtils.e(TAG, "sendSyncConfigCommand: 发送同步指令异常", e);
}
}
/**
* 判断服务是否运行适配API30+ ActivityManager限制
*/
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
if (context == null || serviceClass == null) {
LogUtils.w(TAG, "isServiceRunning: Context/服务类为空返回false");
return false;
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) {
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败返回false");
return false;
}
// API30+ 兼容getRunningServices失效通过进程状态判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try { try {
// 替代方案1通过进程名判断简单兼容
String packageName = context.getPackageName(); String packageName = context.getPackageName();
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses(); List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
if (processes != null && !processes.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo process : processes) { for (ActivityManager.RunningAppProcessInfo process : processes) {
if (process.processName.equals(packageName) && process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) { if (packageName.equals(process.processName)
&& process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
return true; return true;
} }
} }
// 替代方案2兜底判断若进程在运行且服务已启动视为运行中 }
// 兜底:进程存活则视为服务运行(适配部分机型)
return true; return true;
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "isServiceRunning: API30+ 判断服务状态异常", e); LogUtils.e(TAG, "isServiceRunning: API30+ 判断服务状态异常", e);
return false; return false;
} }
} else { } else {
// API30-通过RunningServiceInfo判断
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100); List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);
if (runningServices != null && !runningServices.isEmpty()) {
String serviceClassName = serviceClass.getName();
for (ActivityManager.RunningServiceInfo info : runningServices) { for (ActivityManager.RunningServiceInfo info : runningServices) {
if (serviceClass.getName().equals(info.service.getClassName())) { if (serviceClassName.equals(info.service.getClassName())) {
return true; return true;
} }
} }
}
return false; return false;
} }
} }
// 引导开启忽略电池优化 - 优化:加权限判断+异常捕获 /**
* 引导用户开启忽略电池优化避免服务被后台杀死适配API23+
*/
public static void checkIgnoreBatteryOptimization(Context context) { public static void checkIgnoreBatteryOptimization(Context context) {
if (context == null) return; LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 检查电池优化状态");
if (context == null) {
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: Context为空跳过检查");
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (powerManager == null) return; if (powerManager == null) {
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: PowerManager获取失败跳过检查");
return;
}
try { try {
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(context.getPackageName()); boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
@@ -328,99 +644,28 @@ public class ControlCenterService extends Service {
intent.setData(Uri.parse("package:" + context.getPackageName())); intent.setData(Uri.parse("package:" + context.getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent); context.startActivity(intent);
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 引导开启忽略电池优化"); LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化");
} else {
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已开启忽略电池优化,无需操作");
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导优化异常(部分机型限制)", e); LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导优化异常(部分机型限制)", e);
} }
} else {
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: API<23无需检查电池优化");
} }
} }
// ====================== 核心 Getter/Setter 方法 ====================== /**
public RemindThread getRemindThread() { * 更新服务配置(对外静态入口,触发线程重启,控制配置从本地读取)
return mRemindThread; */
}
public void setCurrentConfigBean(AppConfigBean configBean) {
if (configBean != null) {
synchronized (mServiceLock) {
this.mCurrentConfigBean = configBean;
syncConfigToRemindThread(); // 更新配置后自动同步线程
LogUtils.d(TAG, "setCurrentConfigBean: 服务配置更新成功");
}
}
}
public NotificationManagerUtils getNotificationManager() {
return mNotificationManager;
}
public NotificationMessage getForegroundNotifyMsg() {
return mForegroundNotifyMsg;
}
public AppConfigBean getCurrentConfigBean() {
return mCurrentConfigBean;
}
public boolean isDestroyed() {
return mIsDestroyed;
}
// ====================== 服务销毁逻辑 - 优化:顺序化释放,避免资源泄漏 ======================
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 服务销毁,释放所有资源");
synchronized (mServiceLock) { // 加锁,避免与重启线程操作冲突
isServiceRunning = false;
mIsDestroyed = true;
// 1. 停止前台服务(顺序:先取消通知 → 再移除前台状态)
if (mNotificationManager != null) {
mNotificationManager.cancelForegroundServiceNotify(); // 取消前台通知
}
try {
stopForeground(STOP_FOREGROUND_REMOVE); // 移除前台服务状态API26+
LogUtils.d(TAG, "onDestroy: 前台服务状态已移除");
} catch (Exception e) {
LogUtils.e(TAG, "onDestroy: 移除前台状态异常", e);
}
// 2. 安全停止提醒线程(彻底终止,无残留)
stopRemindThreadSafely();
// 3. 销毁Handler移除所有任务避免内存泄漏
if (mServiceHandler != null) {
mServiceHandler.removeCallbacksAndMessages(null);
mServiceHandler = null;
LogUtils.d(TAG, "onDestroy: Handler已销毁");
}
// 4. 释放通知资源(调用工具类释放方法)
if (mNotificationManager != null) {
mNotificationManager.release();
mNotificationManager = null;
LogUtils.d(TAG, "onDestroy: 通知资源已释放");
}
// 5. 置空所有引用帮助GC回收
mForegroundNotifyMsg = null;
mCurrentConfigBean = null;
}
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
}
@Override
public IBinder onBind(Intent intent) {
return null; // 无需绑定服务
}
// 更新服务配置(对外入口)- 优化:强化兼容性,加异常捕获
public static void updateStatus(Context context, AppConfigBean configBean) { public static void updateStatus(Context context, AppConfigBean configBean) {
if (context == null || configBean == null) return; LogUtils.d(TAG, "updateStatus: 发送业务配置更新指令");
LogUtils.d(TAG, "updateStatus: 发送配置更新指令"); if (context == null || configBean == null) {
LogUtils.e(TAG, "updateStatus: Context/业务配置为空,发送失败");
return;
}
Intent intent = new Intent(context, ControlCenterService.class); Intent intent = new Intent(context, ControlCenterService.class);
intent.setAction(ACTION_RESTART_REMIND_THREAD); intent.setAction(ACTION_RESTART_REMIND_THREAD);
intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean); intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
@@ -433,10 +678,71 @@ public class ControlCenterService extends Service {
} else { } else {
context.startService(intent); context.startService(intent);
} }
LogUtils.d(TAG, "updateStatus: 配置更新指令发送成功"); LogUtils.d(TAG, "updateStatus: 业务配置更新指令发送成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "updateStatus: 发送指令异常", e); LogUtils.e(TAG, "updateStatus: 发送指令异常", e);
} }
} }
// ================================== Getter/Setter 方法(按需提供,线程安全)=================================
public RemindThread getRemindThread() {
synchronized (mServiceLock) {
return mRemindThread;
}
}
public void setCurrentConfigBean(AppConfigBean configBean) {
LogUtils.d(TAG, "setCurrentConfigBean: 更新服务配置");
if (configBean != null) {
synchronized (mServiceLock) {
this.mCurrentConfigBean = configBean;
syncConfigToRemindThread();
}
LogUtils.d(TAG, "setCurrentConfigBean: 配置更新成功");
} else {
LogUtils.e(TAG, "setCurrentConfigBean: 配置为空,更新失败");
}
}
// 更新服务控制配置(内存+本地持久化同步)
public void setServiceControlBean(ControlCenterServiceBean controlBean) {
LogUtils.d(TAG, "setServiceControlBean: 更新服务控制配置");
if (controlBean != null) {
updateAndSaveServiceControlConfig(controlBean);
} else {
LogUtils.e(TAG, "setServiceControlBean: 控制配置为空,更新失败");
}
}
// 获取服务控制配置(外部查询启用状态)
public ControlCenterServiceBean getServiceControlBean() {
synchronized (mServiceLock) {
return mServiceControlBean;
}
}
public NotificationManagerUtils getNotificationManager() {
synchronized (mServiceLock) {
return mNotificationManager;
}
}
public NotificationMessage getForegroundNotifyMsg() {
synchronized (mServiceLock) {
return mForegroundNotifyMsg;
}
}
public AppConfigBean getCurrentConfigBean() {
synchronized (mServiceLock) {
return mCurrentConfigBean;
}
}
public boolean isDestroyed() {
synchronized (mServiceLock) {
return mIsDestroyed;
}
}
} }

View File

@@ -10,7 +10,7 @@ import java.lang.ref.WeakReference;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:38 * @Date 2025/12/17 13:38
* @Describe 提醒线程(单例模式):统一管理充电/耗电提醒逻辑适配Java7+API30+保障线程安全与内存安全 * @Describe 提醒线程(单例模式):统一管理充电/耗电提醒逻辑适配Java7+API30+发送提醒时同步携带当前电量+充电状态
*/ */
public class RemindThread extends Thread { public class RemindThread extends Thread {
// ================================== 静态常量(置顶,统一管理魔法值)================================= // ================================== 静态常量(置顶,统一管理魔法值)=================================
@@ -18,7 +18,7 @@ public class RemindThread extends Thread {
private static final long INIT_DELAY_TIME = 500L; // 初始化延迟ms等待服务就绪 private static final long INIT_DELAY_TIME = 500L; // 初始化延迟ms等待服务就绪
private static final int MIN_SLEEP_TIME = 500; // 最小检测间隔ms防高频轮询 private static final int MIN_SLEEP_TIME = 500; // 最小检测间隔ms防高频轮询
private static final int DEFAULT_SLEEP_TIME = 1000; // 默认检测间隔ms private static final int DEFAULT_SLEEP_TIME = 1000; // 默认检测间隔ms
private static final long REMIND_INTERVAL = 30000L; // 重复提醒间隔ms防骚扰 private static final long REMIND_INTERVAL = 3000L; // 重复提醒间隔ms防骚扰
private static final int CONFIG_RETRY_MAX = 3; // 配置同步重试次数(兜底) private static final int CONFIG_RETRY_MAX = 3; // 配置同步重试次数(兜底)
// ================================== 单例核心(线程安全,避免复用旧实例)================================= // ================================== 单例核心(线程安全,避免复用旧实例)=================================
@@ -166,17 +166,17 @@ public class RemindThread extends Thread {
continue; continue;
} }
// 充电提醒触发 // 充电提醒触发(新增:携带当前电量+充电状态发送)
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) { if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "触发充电提醒:电量" + quantityOfElectricity + "≥阈值" + chargeReminderValue); LogUtils.d(TAG, "触发充电提醒:充电中,电量" + quantityOfElectricity + "≥阈值" + chargeReminderValue);
sendNotificationMessage("+"); sendNotificationMessage("+", quantityOfElectricity, isCharging);
lastRemindTime = currentTime; lastRemindTime = currentTime;
startRemindRecoveryTimer(); startRemindRecoveryTimer();
} }
// 耗电提醒触发 // 耗电提醒触发(新增:携带当前电量+充电状态发送)
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) { else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "触发耗电提醒:电量" + quantityOfElectricity + "≤阈值" + usageReminderValue); LogUtils.d(TAG, "触发耗电提醒:未充电,电量" + quantityOfElectricity + "≤阈值" + usageReminderValue);
sendNotificationMessage("-"); sendNotificationMessage("-", quantityOfElectricity, isCharging);
lastRemindTime = currentTime; lastRemindTime = currentTime;
startRemindRecoveryTimer(); startRemindRecoveryTimer();
} }
@@ -228,10 +228,13 @@ public class RemindThread extends Thread {
} }
/** /**
* 发送提醒消息弱引用Handler+Message复用防泄漏 * 发送提醒消息(新增:携带当前电量+充电状态,弱引用Handler+Message复用防泄漏
* @param type 提醒类型(+:充电提醒,-:耗电提醒)
* @param battery 当前电量0-100
* @param isCharging 当前充电状态true=充电中)
*/ */
private void sendNotificationMessage(String content) { private void sendNotificationMessage(String type, int battery, boolean isCharging) {
LogUtils.d(TAG, "准备发送提醒消息:" + content); LogUtils.d(TAG, "准备发送提醒消息:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
if (isExist || !isReminding) { if (isExist || !isReminding) {
LogUtils.d(TAG, "线程退出/提醒关闭,跳过发送"); LogUtils.d(TAG, "线程退出/提醒关闭,跳过发送");
return; return;
@@ -243,10 +246,14 @@ public class RemindThread extends Thread {
return; return;
} }
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT, content); // 构建消息what=提醒标识obj=类型arg1=当前电量arg2=充电状态0=未充电1=充电中)
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT);
message.obj = type;
message.arg1 = battery;
message.arg2 = isCharging ? 1 : 0; // boolean转intMessage无boolean参数兼容Java7
try { try {
handler.sendMessage(message); handler.sendMessage(message);
LogUtils.d(TAG, "提醒消息发送成功"); LogUtils.d(TAG, "提醒消息发送成功:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "消息发送异常", e); LogUtils.e(TAG, "消息发送异常", e);
if (message != null) message.recycle(); if (message != null) message.recycle();