电量提醒线程测试完成。

This commit is contained in:
2025-12-20 17:40:06 +08:00
parent 65acbfcd04
commit 28d340a772
4 changed files with 152 additions and 213 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sat Dec 20 08:27:44 GMT 2025
#Sat Dec 20 09:38:35 GMT 2025
stageCount=10
libraryProject=
baseVersion=15.14
publishVersion=15.14.9
buildCount=70
buildCount=76
baseBetaVersion=15.14.10

View File

@@ -108,12 +108,11 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
return;
}
// 3. 同步电池状态到服务,触发线程更新
service.notifyBatteryStateChanged(currentCharging, currentBatteryLevel);
// 4. 更新静态缓存状态,保证多线程可见
sIsCharging = currentCharging;
sLastBatteryLevel = currentBatteryLevel;
handleNotifyAppConfigUpdate(service);
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功 | 缓存电量=" + sLastBatteryLevel + "% | 缓存充电状态=" + sIsCharging);
} catch (Exception e) {

View File

@@ -85,7 +85,7 @@ public class ControlCenterService extends Service {
// 资源释放顺序:前台服务 → 线程 → 广播接收器 → Handler → 通知 → 引用(避免内存泄漏)
stopForegroundService();
RemindThread.stopRemindThreadSafely();
RemindThread.stopRemindThread();
releaseBroadcastReceiver();
destroyHandler();
releaseNotificationResource();
@@ -471,21 +471,6 @@ public class ControlCenterService extends Service {
}
}
/**
* 接收电池状态变化,同步到提醒线程
* @param isCharging 是否充电中
* @param lastBatteryLevel 最新电池电量
*/
public void notifyBatteryStateChanged(boolean isCharging, int lastBatteryLevel) {
LogUtils.d(TAG, "notifyBatteryStateChanged执行 | 充电中=" + isCharging + " | 电量=" + lastBatteryLevel);
if (mServiceHandler != null) {
RemindThread.startRemindThreadWithBatteryInfo(this, mServiceHandler, isCharging, lastBatteryLevel);
LogUtils.d(TAG, "notifyBatteryStateChanged电池状态已同步到提醒线程");
} else {
LogUtils.w(TAG, "notifyBatteryStateChangedHandler未初始化同步失败");
}
}
// ================================== Getter 方法按需开放避免冗余Setter=================================
public ControlCenterServiceBean getServiceControlBean() {
return mServiceControlBean;

View File

@@ -6,12 +6,14 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.models.AppConfigBean;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
* 提醒线程(线程安全单例
* 提醒线程(多实例列表管理
* 功能:管理充电/耗电提醒逻辑触发条件时向Handler发送提醒消息
* 适配Java7 | API30 | 内存泄漏防护 | 多线程状态同步
* 对外接口:{@link #startRemindThreadWithAppConfig(Context, ControlCenterServiceHandler, AppConfigBean)}、{@link #startRemindThreadWithBatteryInfo(Context, ControlCenterServiceHandler, boolean, int)}、{@link #stopRemindThreadSafely()}
* 对外接口:{@link #startRemindThreadWithAppConfig(Context, ControlCenterServiceHandler, AppConfigBean)}、{
* @link #startRemindThreadWithBatteryInfo(Context, ControlCenterServiceHandler, boolean, int)}、{@link #stopRemindThread()}
*/
public class RemindThread extends Thread {
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
@@ -30,17 +32,20 @@ public class RemindThread extends Thread {
private static final String REMIND_TYPE_CHARGE = "+";
private static final String REMIND_TYPE_USAGE = "-";
// ================================== 单例核心(双重校验锁,保证线程安全=================================
private static volatile RemindThread sInstance;
// ================================== 静态成员(多实例列表管理=================================
private static volatile ArrayList<RemindThread> sRemindThreadList;
// ================================== 成员变量区按功能分层volatile保证多线程可见性=================================
// 并发安全锁(保护线程状态变更)
private final Object mRemindLock = new Object();
// 弱引用依赖防内存泄漏ApplicationContext 避免 Activity 引用)
private Context mContext;
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
// 线程状态标记volatile 确保多线程可见)
private volatile boolean isExist;
private volatile boolean isReminding;
public volatile boolean isExist;
// 业务配置参数volatile 确保配置变更实时生效)
private volatile boolean isEnableChargeReminder;
@@ -51,173 +56,136 @@ public class RemindThread extends Thread {
private volatile int quantityOfElectricity;
private volatile boolean isCharging;
// 并发安全锁(保护线程状态变更)
private final static Object sRemindLock = new Object();
// ================================== 私有构造器(单例专用,禁止外部实例化)=================================
// ================================== 私有构造器(禁止外部实例化)=================================
private RemindThread(Context context, ControlCenterServiceHandler handler) {
LogUtils.d(TAG, "构造方法执行 | threadId=" + getId() + " | threadName=" + getName());
LogUtils.d(TAG, "构造器调用 | context=" + context + " | handler=" + handler);
this.mContext = context.getApplicationContext();
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
resetThreadStateInternal();
LogUtils.d(TAG, "构造完成 | 初始状态重置成功");
LogUtils.d(TAG, "构造完成 | threadId=" + getId() + " | 初始状态重置成功");
}
// ================================== 单例获取方法(核心,双重校验锁=================================
/**
* 获取单例实例,保证全局唯一
* @param context 上下文使用ApplicationContext
* @param handler 服务处理器
* @return 唯一的 RemindThread 实例
*/
private static RemindThread getInstance(Context context, ControlCenterServiceHandler handler) {
if (sInstance == null) {
synchronized (RemindThread.class) {
if (sInstance == null) {
sInstance = new RemindThread(context, handler);
LogUtils.d(TAG, "单例创建成功 | threadId=" + sInstance.getId());
}
}
}
return sInstance;
}
// ================================== 对外公开静态接口(基于单例,统一线程管理)=================================
// ================================== 对外公开静态接口(多实例列表管理=================================
/**
* 启动提醒线程,同步最新配置
* 逻辑:停止所有旧线程 → 创建新线程 → 加入列表管理
* @param context 上下文(非空)
* @param handler 服务处理器(非空)
* @param config 应用配置Bean非空
* @return true: 启动成功/已在运行false: 入参非法
* @return true: 启动成功false: 入参非法
*/
public static boolean startRemindThreadWithAppConfig(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
LogUtils.d(TAG, "startRemindThreadWithAppConfig执行 | context=" + context + " | handler=" + handler + " | config=" + config);
synchronized (RemindThread.class) {
// 入参严格校验
if (context == null || handler == null || config == null) {
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler + " | config=" + config);
return false;
}
LogUtils.d(TAG, "startRemindThreadWithAppConfig调用 | context=" + context + " | handler=" + handler + " | config=" + config);
RemindThread instance = getInstance(context, handler);
// 已在提醒状态,仅同步配置
if (instance.isReminding) {
instance.setAppConfigBean(config);
LogUtils.d(TAG, "线程已在运行,同步最新配置 | threadId=" + instance.getId());
return true;
}
// 同步配置并启动线程
instance.setAppConfigBean(config);
if (!instance.isRunning()) {
instance.isExist = false;
instance.start();
LogUtils.d(TAG, "线程启动成功 | threadId=" + instance.getId());
return true;
} else {
LogUtils.d(TAG, "线程已在运行状态 | threadId=" + instance.getId());
return true;
}
}
}
/**
* 启动提醒线程,同步电池信息
* @param context 上下文(非空)
* @param handler 服务处理器(非空)
* @param isCharging 充电状态
* @param lastBatteryLevel 最新电量
* @return true: 启动成功/已在运行false: 入参非法
*/
public static boolean startRemindThreadWithBatteryInfo(Context context, ControlCenterServiceHandler handler, boolean isCharging, int lastBatteryLevel) {
LogUtils.d(TAG, "startRemindThreadWithBatteryInfo执行 | context=" + context + " | handler=" + handler + " | isCharging=" + isCharging + " | lastBatteryLevel=" + lastBatteryLevel);
synchronized (RemindThread.class) {
// 入参严格校验
if (context == null || handler == null) {
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler);
return false;
}
RemindThread instance = getInstance(context, handler);
// 已在提醒状态,仅同步电池信息
if (instance.isReminding) {
instance.isCharging = isCharging;
instance.quantityOfElectricity = lastBatteryLevel;
LogUtils.d(TAG, "线程已在运行,同步电池信息 | threadId=" + instance.getId() + " | isCharging=" + isCharging + " | lastBatteryLevel=" + lastBatteryLevel);
return true;
}
// 同步电池信息并启动线程
instance.isCharging = isCharging;
instance.quantityOfElectricity = lastBatteryLevel;
if (!instance.isRunning()) {
instance.isExist = false;
instance.start();
LogUtils.d(TAG, "线程启动成功 | threadId=" + instance.getId());
return true;
} else {
LogUtils.d(TAG, "线程已在运行状态 | threadId=" + instance.getId());
return true;
}
}
}
/**
* 安全停止线程,优雅销毁单例
*/
public static void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely执行 | 单例存在=" + (sInstance != null));
synchronized (RemindThread.class) {
if (sInstance == null) {
LogUtils.w(TAG, "停止失败:线程实例为空");
return;
}
// 线程未运行,直接销毁
if (!sInstance.isRunning()) {
LogUtils.d(TAG, "线程未运行,直接销毁 | threadId=" + sInstance.getId());
destroyInstance();
return;
}
// 标记退出,等待线程自然结束
sInstance.isExist = true;
sInstance.isReminding = false;
LogUtils.d(TAG, "标记线程退出,等待结束 | threadId=" + sInstance.getId());
try {
sInstance.join(THREAD_JOIN_TIMEOUT);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.e(TAG, "等待线程退出被中断", e);
}
// 销毁单例释放资源
destroyInstance();
LogUtils.d(TAG, "线程安全销毁完成");
// 入参严格校验
if (context == null || handler == null || config == null) {
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler + " | config=" + config);
return false;
}
}
// ================================== 私有单例管理方法=================================
/**
* 销毁单例,释放所有资源
*/
private static void destroyInstance() {
synchronized (RemindThread.class) {
if (sInstance != null) {
sInstance.isExist = true;
sInstance.isReminding = false;
// 中断存活线程
if (sInstance.isAlive()) {
sInstance.interrupt();
LogUtils.d(TAG, "中断存活线程 | threadId=" + sInstance.getId());
// 初始化线程列表
if (sRemindThreadList == null) {
synchronized (RemindThread.class) {
if (sRemindThreadList == null) {
sRemindThreadList = new ArrayList<RemindThread>();
LogUtils.d(TAG, "线程列表初始化完成");
}
// 释放线程内部资源
sInstance.releaseResourcesInternal();
sInstance = null;
LogUtils.d(TAG, "单例销毁完成");
}
}
// 停止所有旧线程
stopAllOldThreadsInternal();
// 创建并启动新线程
RemindThread newRemindThread = new RemindThread(context, handler);
newRemindThread.setAppConfigBean(config);
newRemindThread.isExist = false;
newRemindThread.start();
sRemindThreadList.add(newRemindThread);
LogUtils.d(TAG, "新线程启动成功 | threadId=" + newRemindThread.getId() + " | 列表大小=" + sRemindThreadList.size());
return true;
}
/**
* 启动提醒线程,同步电池状态信息
* 逻辑:停止所有旧线程 → 创建新线程 → 同步电池状态 → 加入列表管理
* @param context 上下文(非空)
* @param handler 服务处理器(非空)
* @param isCharging 充电状态
* @param batteryLevel 当前电量
* @return true: 启动成功false: 入参非法
*/
public static boolean startRemindThreadWithBatteryInfo(Context context, ControlCenterServiceHandler handler, boolean isCharging, int batteryLevel) {
LogUtils.d(TAG, "startRemindThreadWithBatteryInfo调用 | context=" + context + " | handler=" + handler + " | isCharging=" + isCharging + " | batteryLevel=" + batteryLevel);
// 入参严格校验
if (context == null || handler == null) {
LogUtils.e(TAG, "启动失败:入参为空 | context=" + context + " | handler=" + handler);
return false;
}
// 初始化线程列表
if (sRemindThreadList == null) {
synchronized (RemindThread.class) {
if (sRemindThreadList == null) {
sRemindThreadList = new ArrayList<RemindThread>();
LogUtils.d(TAG, "线程列表初始化完成");
}
}
}
// 停止所有旧线程
stopAllOldThreadsInternal();
// 创建并启动新线程
RemindThread newRemindThread = new RemindThread(context, handler);
// 同步电池状态
newRemindThread.isCharging = isCharging;
newRemindThread.quantityOfElectricity = Math.min(Math.max(batteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
newRemindThread.isExist = false;
newRemindThread.start();
sRemindThreadList.add(newRemindThread);
LogUtils.d(TAG, "新线程启动成功 | threadId=" + newRemindThread.getId() + " | 电池状态同步完成");
return true;
}
/**
* 安全停止所有线程,清空列表
*/
public static void stopRemindThread() {
LogUtils.d(TAG, "stopRemindThread调用 | 列表存在=" + (sRemindThreadList != null) + " | 列表大小=" + (sRemindThreadList != null ? sRemindThreadList.size() : 0));
if (sRemindThreadList == null || sRemindThreadList.isEmpty()) {
LogUtils.w(TAG, "停止失败:线程列表为空");
return;
}
// 标记所有线程退出
for (RemindThread remindThread : sRemindThreadList) {
remindThread.isExist = true;
LogUtils.d(TAG, "标记线程退出 | threadId=" + remindThread.getId());
}
// 清空列表
sRemindThreadList.clear();
LogUtils.d(TAG, "所有线程已标记退出,列表已清空");
}
// ================================== 私有静态辅助方法(多实例管理)=================================
/**
* 停止所有旧线程并清空列表
*/
private static void stopAllOldThreadsInternal() {
if (sRemindThreadList == null || sRemindThreadList.isEmpty()) {
return;
}
// 标记所有旧线程退出
for (RemindThread remindThread : sRemindThreadList) {
remindThread.isExist = true;
LogUtils.d(TAG, "标记旧线程退出 | threadId=" + remindThread.getId());
}
// 清空旧线程列表
sRemindThreadList.clear();
LogUtils.d(TAG, "旧线程已全部标记退出,列表已清空");
}
// ================================== 线程核心运行逻辑=================================
@@ -226,15 +194,16 @@ public class RemindThread extends Thread {
LogUtils.d(TAG, "run执行 | threadId=" + getId() + " | 状态=" + getState());
// 初始化提醒状态(加锁保护,避免多线程竞争)
synchronized (sRemindLock) {
synchronized (mRemindLock) {
if (isReminding) {
LogUtils.w(TAG, "线程已在提醒状态,退出运行 | threadId=" + getId());
return;
}
isReminding = true;
isReminding = true;
}
// 核心电量检测循环
LogUtils.d(TAG, "进入电量检测循环 | 休眠时间=" + sleepTime + "ms");
LogUtils.d(TAG, "进入电量检测循环 | 休眠时间=" + sleepTime + "ms | threadId=" + getId());
while (!isExist) {
try {
// 快速退出判断
@@ -242,24 +211,24 @@ public class RemindThread extends Thread {
// 电量有效性校验非0-100视为无效退出电量提醒线程
if (quantityOfElectricity < BATTERY_LEVEL_MIN || quantityOfElectricity > BATTERY_LEVEL_MAX) {
LogUtils.w(TAG, "电量无效,退出电量提醒线程 | 当前电量=" + quantityOfElectricity);
LogUtils.w(TAG, "电量无效,退出电量提醒线程 | 当前电量=" + quantityOfElectricity + " | threadId=" + getId());
break;
}
// 充电提醒触发逻辑
// 充电/耗电提醒触发逻辑
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "触发充电提醒 | 当前电量=" + quantityOfElectricity + " ≥ 阈值=" + chargeReminderValue);
LogUtils.d(TAG, "触发充电提醒 | 当前电量=" + quantityOfElectricity + " ≥ 阈值=" + chargeReminderValue + " | threadId=" + getId());
sendNotificationMessageInternal(REMIND_TYPE_CHARGE, quantityOfElectricity, isCharging);
} else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + " ≤ 阈值=" + usageReminderValue);
LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + " ≤ 阈值=" + usageReminderValue + " | threadId=" + getId());
sendNotificationMessageInternal(REMIND_TYPE_USAGE, quantityOfElectricity, isCharging);
}
// 安全休眠,保留中断标记
safeSleepInternal(sleepTime);
} catch (Exception e) {
LogUtils.e(TAG, "循环运行异常,退出电量提醒线程 | 当前电量=" + quantityOfElectricity);
break;
LogUtils.e(TAG, "循环运行异常,退出电量提醒线程 | 当前电量=" + quantityOfElectricity + " | threadId=" + getId(), e);
break;
}
}
@@ -276,17 +245,17 @@ public class RemindThread extends Thread {
* @param isCharging 充电状态
*/
private void sendNotificationMessageInternal(String type, int battery, boolean isCharging) {
LogUtils.d(TAG, "sendNotificationMessageInternal执行 | 类型=" + type + " | 电量=" + battery + " | isCharging=" + isCharging);
LogUtils.d(TAG, "sendNotificationMessageInternal调用 | 类型=" + type + " | 电量=" + battery + " | isCharging=" + isCharging + " | threadId=" + getId());
// 前置状态校验
if (isExist || !isReminding) {
LogUtils.d(TAG, "消息发送跳过:线程已退出或提醒关闭");
LogUtils.d(TAG, "消息发送跳过:线程已退出或提醒关闭 | threadId=" + getId());
return;
}
// 获取弱引用的Handler
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler.get();
if (handler == null) {
LogUtils.w(TAG, "消息发送失败Handler已被回收");
LogUtils.w(TAG, "消息发送失败Handler已被回收 | threadId=" + getId());
return;
}
@@ -297,9 +266,9 @@ public class RemindThread extends Thread {
try {
handler.sendMessage(message);
LogUtils.d(TAG, "提醒消息发送成功 | 类型=" + type + " | 电量=" + battery);
LogUtils.d(TAG, "提醒消息发送成功 | 类型=" + type + " | 电量=" + battery + " | threadId=" + getId());
} catch (Exception e) {
LogUtils.e(TAG, "消息发送异常", e);
LogUtils.e(TAG, "消息发送异常 | threadId=" + getId(), e);
// 异常时回收Message避免内存泄漏
if (message != null) {
message.recycle();
@@ -312,11 +281,12 @@ public class RemindThread extends Thread {
* @param millis 休眠时长(ms)
*/
private void safeSleepInternal(long millis) {
LogUtils.d(TAG, "safeSleepInternal调用 | 休眠时长=" + millis + "ms | threadId=" + getId());
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.w(TAG, "休眠被中断,线程准备退出");
LogUtils.w(TAG, "休眠被中断,线程准备退出 | threadId=" + getId());
}
}
@@ -324,7 +294,7 @@ public class RemindThread extends Thread {
* 重置线程初始状态(构造器专用)
*/
private void resetThreadStateInternal() {
LogUtils.d(TAG, "resetThreadStateInternal执行");
LogUtils.d(TAG, "resetThreadStateInternal调用 | threadId=" + getId());
// 状态标记初始化
isExist = false;
isReminding = false;
@@ -336,13 +306,14 @@ public class RemindThread extends Thread {
usageReminderValue = -1;
quantityOfElectricity = INVALID_BATTERY_VALUE;
isCharging = false;
LogUtils.d(TAG, "线程初始状态重置完成 | threadId=" + getId());
}
/**
* 清理线程运行状态(循环退出时调用)
*/
private void cleanThreadStateInternal() {
LogUtils.d(TAG, "cleanThreadStateInternal执行");
LogUtils.d(TAG, "cleanThreadStateInternal调用 | threadId=" + getId());
isReminding = false;
isExist = true;
quantityOfElectricity = INVALID_BATTERY_VALUE;
@@ -350,6 +321,7 @@ public class RemindThread extends Thread {
if (isAlive()) {
interrupt();
}
LogUtils.d(TAG, "线程运行状态清理完成 | threadId=" + getId());
}
/**
@@ -357,9 +329,9 @@ public class RemindThread extends Thread {
* @param config 应用配置Bean
*/
public void setAppConfigBean(AppConfigBean config) {
LogUtils.d(TAG, "setAppConfigBean执行 | config=" + config);
LogUtils.d(TAG, "setAppConfigBean调用 | config=" + config + " | threadId=" + getId());
if (config == null) {
LogUtils.e(TAG, "配置同步失败配置Bean为空");
LogUtils.e(TAG, "配置同步失败配置Bean为空 | threadId=" + getId());
quantityOfElectricity = INVALID_BATTERY_VALUE;
return;
}
@@ -373,25 +345,8 @@ public class RemindThread extends Thread {
quantityOfElectricity = (config.getCurrentBatteryValue() >= BATTERY_LEVEL_MIN && config.getCurrentBatteryValue() <= BATTERY_LEVEL_MAX)
? config.getCurrentBatteryValue() : INVALID_BATTERY_VALUE;
isCharging = config.isCharging();
isReminding = isEnableChargeReminder || isEnableUsageReminder;
LogUtils.d(TAG, "配置同步完成 | 休眠时间=" + sleepTime + "ms | 提醒开启=" + isReminding + " | 当前电量=" + quantityOfElectricity + " | 充电阈值=" + chargeReminderValue + " | 耗电阈值=" + usageReminderValue);
}
/**
* 释放线程内部资源,杜绝内存泄漏
*/
private void releaseResourcesInternal() {
LogUtils.d(TAG, "releaseResourcesInternal执行");
// 释放上下文引用
mContext = null;
// 清空WeakReference
if (mwrControlCenterServiceHandler != null) {
mwrControlCenterServiceHandler.clear();
mwrControlCenterServiceHandler = null;
}
// 清理线程状态
cleanThreadStateInternal();
LogUtils.d(TAG, "配置同步完成 | 休眠时间=" + sleepTime + "ms | 提醒开启=" + isReminding + " | 当前电量=" + quantityOfElectricity + " | 充电阈值=" + chargeReminderValue + " | 耗电阈值=" + usageReminderValue + " | threadId=" + getId());
}
/**
@@ -400,13 +355,13 @@ public class RemindThread extends Thread {
*/
private boolean isRunning() {
boolean running = !isExist && isAlive();
LogUtils.d(TAG, "isRunning执行 | 运行中=" + running + " | 退出标记=" + isExist + " | 存活=" + isAlive());
LogUtils.d(TAG, "isRunning调用 | 运行中=" + running + " | 退出标记=" + isExist + " | 存活=" + isAlive() + " | threadId=" + getId());
return running;
}
// ================================== Getter/Setter按需开放=================================
public void setIsExist(boolean isExist) {
LogUtils.d(TAG, "setIsExist执行 | isExist=" + isExist);
LogUtils.d(TAG, "setIsExist调用 | isExist=" + isExist + " | threadId=" + getId());
this.isExist = isExist;
}