重置通知架构为旧式方法,用线程启动法。过程顺便整理代码。

This commit is contained in:
2025-12-19 20:31:43 +08:00
parent e584e824c0
commit bea77409a5
8 changed files with 405 additions and 373 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Dec 19 10:40:58 GMT 2025
#Fri Dec 19 10:59:14 GMT 2025
stageCount=10
libraryProject=
baseVersion=15.14
publishVersion=15.14.9
buildCount=43
buildCount=44
baseBetaVersion=15.14.10

View File

@@ -28,11 +28,9 @@ import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
import cc.winboll.studio.powerbell.activities.SettingsActivity;
import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
import cc.winboll.studio.powerbell.models.AppConfigBean;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.threads.RemindThread;
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
@@ -42,24 +40,24 @@ import cc.winboll.studio.powerbell.views.MainContentView;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:14
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
* 适配Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
* 核心规则UI开关直接联动服务启停本地配置与服务状态实时同步
* @Date 2025/12/19 20:26
* @Describe 应用核心主活动
* 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能
* 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
*/
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
public static final String TAG = "MainActivity";
// 请求码
// 请求码常量
private static final int REQUEST_READ_MEDIA_IMAGES = 1001;
// 延迟时间
// 延迟加载常量
private static final long DELAY_LOAD_NON_CRITICAL = 500L;
// Handler消息标识按业务优先级排序
public static final int MSG_RELOAD_APPCONFIG = 0;
public static final int MSG_CURRENTVALUEBATTERY = 1;
public static final int MSG_LOAD_BACKGROUND = 2;
private static final int MSG_START_REMIND_THREAD = 3;
private static final int MSG_UPDATE_SERVICE_SWITCH = 4;
private static final int MSG_UPDATE_SERVICE_SWITCH = 3;
// ======================== 静态成员(全局共享,严格管控生命周期)========================
private static MainActivity sMainActivity;
@@ -95,8 +93,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: start");
LogUtils.d(TAG, "onCreate: 页面启动,开始初始化流程");
super.onCreate(savedInstanceState);
// 优先初始化全局Handler避免消息丢失
initGlobalHandler();
// 布局与核心流程初始化
@@ -106,45 +105,41 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
initCriticalView();
initCoreUtilsAsync();
loadNonCriticalViewDelayed();
LogUtils.d(TAG, "onCreate: end");
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onPostCreate: start");
super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: end");
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume: start");
super.onResume();
LogUtils.d(TAG, "onResume: 恢复页面状态");
// 恢复背景与服务开关UI
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "onResume: send MSG_LOAD_BACKGROUND & MSG_UPDATE_SERVICE_SWITCH");
LogUtils.d(TAG, "onResume: 发送背景加载与服务开关更新消息");
}
// 恢复广告
if (mADsBannerView != null) {
mADsBannerView.resumeADs(this);
}
LogUtils.d(TAG, "onResume: end");
}
@Override
protected void onPause() {
LogUtils.d(TAG, "onPause: start");
super.onPause();
LogUtils.d(TAG, "onPause: end");
LogUtils.d(TAG, "onPause: 页面暂停");
}
@Override
protected void onDestroy() {
LogUtils.d(TAG, "onDestroy: start");
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 开始释放资源");
// 释放广告资源
if (mADsBannerView != null) {
mADsBannerView.releaseAdResources();
@@ -155,17 +150,18 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView.releaseResources();
mMainContentView = null;
}
// 销毁Handler
// 销毁Handler,防止内存泄漏
if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 全局Handler已销毁");
}
// 释放Drawable防止内存泄漏
// 释放Drawable清空回调
if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null);
mFrameDrawable = null;
}
// 置空所有引用
// 置空所有引用帮助GC回收
sMainActivity = null;
mPermissionUtils = null;
mAppConfigUtils = null;
@@ -175,24 +171,25 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mApplication = null;
mToolbar = null;
mAdsViewStub = null;
LogUtils.d(TAG, "onDestroy: end");
LogUtils.d(TAG, "onDestroy: 所有资源释放完成");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode);
super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 背景设置完成后重新加载
if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送重新加载消息");
}
}
// ======================== 菜单与导航方法 ========================
@Override
public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu: start");
LogUtils.d(TAG, "onCreateOptionsMenu: 初始化菜单");
mMenu = menu;
AESThemeUtil.inflateMenu(this, menu);
if (App.isDebugging()) {
@@ -200,7 +197,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
}
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: end");
return true;
}
@@ -250,7 +246,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void onBackPressed() {
moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: app move to background");
LogUtils.d(TAG, "onBackPressed: 应用退至后台");
}
@Override
@@ -260,23 +256,22 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 核心初始化方法 ========================
private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: start");
LogUtils.d(TAG, "initPermissionUtils: 初始化权限工具类");
mPermissionUtils = PermissionUtils.getInstance();
LogUtils.d(TAG, "initPermissionUtils: end");
}
private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: start");
LogUtils.d(TAG, "initGlobalHandler: 初始化全局Handler");
if (sGlobalHandler == null) {
sGlobalHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity destroyed, skip msg what=" + msg.what);
LogUtils.w(TAG, "handleMessage: Activity已销毁,跳过消息 what=" + msg.what);
return;
}
LogUtils.d(TAG, "handleMessage: receive msg what=" + msg.what);
LogUtils.d(TAG, "handleMessage: 处理消息 what=" + msg.what);
switch (msg.what) {
case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData();
@@ -290,30 +285,24 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sMainActivity.reloadBackground();
sMainActivity.setMainLayoutBackgroundColor();
break;
case MSG_START_REMIND_THREAD:
AppConfigBean configBean = (AppConfigBean) msg.obj;
LogUtils.d(TAG, "MSG_START_REMIND_THREAD not yet.");
break;
case MSG_UPDATE_SERVICE_SWITCH:
sMainActivity.updateServiceSwitchUI();
break;
}
}
};
LogUtils.d(TAG, "initGlobalHandler: handler created");
LogUtils.d(TAG, "initGlobalHandler: 全局Handler创建成功");
}
LogUtils.d(TAG, "initGlobalHandler: end");
}
private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: start");
LogUtils.d(TAG, "initMainContentView: 初始化核心视图");
View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this);
LogUtils.d(TAG, "initMainContentView: MainContentView created");
}
private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: start");
LogUtils.d(TAG, "initCriticalView: 初始化关键视图组件");
sMainActivity = this;
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
@@ -321,15 +310,14 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
}
mAdsViewStub = findViewById(R.id.stub_ads_banner);
LogUtils.d(TAG, "initCriticalView: end");
}
private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: start");
LogUtils.d(TAG, "initCoreUtilsAsync: 异步初始化核心工具类");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: async thread start");
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
@@ -339,7 +327,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: create default service config (disabled)");
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无配置,创建默认禁用配置");
}
// 根据配置启停服务
@@ -350,7 +338,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void run() {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: start service by config");
LogUtils.d(TAG, "initCoreUtilsAsync: 配置启用服务,启动服务");
}
});
} else if (!isServiceEnable && isServiceAlive) {
@@ -358,7 +346,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: stop service by config");
LogUtils.d(TAG, "initCoreUtilsAsync: 配置禁用服务,停止服务");
}
});
}
@@ -368,7 +356,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void run() {
if (isFinishing() || isDestroyed()) {
LogUtils.w(TAG, "initCoreUtilsAsync: Activity destroyed, skip UI update");
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
return;
}
// 加载框架背景
@@ -382,14 +370,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
}
});
LogUtils.d(TAG, "initCoreUtilsAsync: async thread end");
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程执行完成");
}
}).start();
LogUtils.d(TAG, "initCoreUtilsAsync: end");
}
private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: start");
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 延迟加载非核心视图");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
@@ -399,38 +386,35 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
loadAdsView();
}
}, DELAY_LOAD_NON_CRITICAL);
LogUtils.d(TAG, "loadNonCriticalViewDelayed: end");
}
// ======================== 视图操作方法 ========================
private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: start");
LogUtils.d(TAG, "loadAdsView: 加载广告视图");
if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: AdsViewStub is null");
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空");
return;
}
if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: ADsBannerView created");
LogUtils.d(TAG, "loadAdsView: 广告视图创建成功");
}
LogUtils.d(TAG, "loadAdsView: end");
}
private void updateViewData() {
LogUtils.d(TAG, "updateViewData: start");
LogUtils.d(TAG, "updateViewData: 更新视图数据");
if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: MainContentView or FrameDrawable is null");
LogUtils.e(TAG, "updateViewData: 核心视图或框架背景为空,更新失败");
return;
}
mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: view data updated");
}
private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: start");
LogUtils.d(TAG, "reloadBackground: 重新加载背景");
if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: MainContentView or BackgroundSourceUtils is null");
LogUtils.e(TAG, "reloadBackground: 核心视图或背景工具类为空,加载失败");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
@@ -438,115 +422,86 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
} else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
LogUtils.w(TAG, "reloadBackground: 无自定义背景,使用默认背景");
}
LogUtils.d(TAG, "reloadBackground: end");
}
private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: start");
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 设置主布局背景色");
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: invalid context");
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
}
LogUtils.d(TAG, "setMainLayoutBackgroundColor: end");
}
private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI: start");
LogUtils.d(TAG, "updateServiceSwitchUI: 更新服务开关UI状态");
if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: MainContentView or ServiceControlBean is null");
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图或服务配置为空,更新失败");
return;
}
boolean configEnabled = mServiceControlBean.isEnableService();
LogUtils.d(TAG, "updateServiceSwitchUI: config enabled=" + configEnabled);
LogUtils.d(TAG, "updateServiceSwitchUI: 服务配置启用状态=" + configEnabled);
mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: end");
}
// ======================== 服务与线程管理方法 ========================
// private void restartRemindThread(AppConfigBean configBean) {
// LogUtils.d(TAG, "restartRemindThread: start, configBean=" + configBean);
// if (configBean == null || mServiceControlBean == null) {
// LogUtils.e(TAG, "restartRemindThread: configBean or ServiceControlBean is null");
// return;
// }
// if (!mServiceControlBean.isEnableService()) {
// LogUtils.w(TAG, "restartRemindThread: service is disabled, skip");
// return;
// }
// if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
// ControlCenterService.startControlCenterService(getApplicationContext());
// }
// RemindThread.destroyInstance();
// ControlCenterService.updateStatus(getApplicationContext(), configBean);
// LogUtils.d(TAG, "restartRemindThread: end");
// }
private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: target state=" + isEnable);
LogUtils.d(TAG, "toggleServiceEnableState: 切换服务状态,目标状态=" + isEnable);
if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: ServiceControlBean is null");
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return;
}
mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
// ========== 核心新增逻辑:UI开关联动服务启停 + 线程销毁 ==========
// UI开关联动服务启停 + 线程销毁
if (isEnable) {
// 开启:启动服务
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: start service success");
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动");
}
} else {
// 关闭:停止服务 + 销毁线程
// 关闭:停止服务
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: stop service + destroy thread success");
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
}
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "toggleServiceEnableState: config saved + service state synced");
}
// ======================== 页面跳转方法 ========================
private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: start");
LogUtils.d(TAG, "startAboutActivity: 启动关于页面");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
LogUtils.d(TAG, "startAboutActivity: end");
}
// ======================== 消息发送方法 ========================
private void sendRestartRemindThreadMessage() {
LogUtils.d(TAG, "sendRestartRemindThreadMessage: start");
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
LogUtils.e(TAG, "sendRestartRemindThreadMessage: invalid context");
return;
}
Message msg = sGlobalHandler.obtainMessage(MSG_START_REMIND_THREAD);
msg.obj = mAppConfigUtils.mAppConfigBean;
sGlobalHandler.sendMessage(msg);
LogUtils.d(TAG, "sendRestartRemindThreadMessage: msg sent");
private void notifyServiceAppConfigChange() {
LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更");
// 预留配置变更通知逻辑
}
// ======================== 静态工具方法 ========================
public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: send MSG_RELOAD_APPCONFIG");
LogUtils.d(TAG, "reloadAppConfig: 发送配置重载消息");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
}
}
public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: battery=" + value);
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 发送当前电量消息,电量=" + value);
if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value;
@@ -556,9 +511,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 辅助工具方法 ========================
private String getRealPathFromUri(Uri contentUri) {
LogUtils.d(TAG, "getRealPathFromUri: uri=" + contentUri);
LogUtils.d(TAG, "getRealPathFromUri: 解析Uri路径Uri=" + contentUri);
if (contentUri == null) {
LogUtils.e(TAG, "getRealPathFromUri: Uri is null");
LogUtils.e(TAG, "getRealPathFromUri: Uri为空,解析失败");
return null;
}
String realPath = null;
@@ -576,12 +531,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
cursor.close();
}
}
LogUtils.d(TAG, "getRealPathFromUri: path=" + realPath);
LogUtils.d(TAG, "getRealPathFromUri: 解析完成,路径=" + realPath);
return realPath;
}
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: start");
LogUtils.d(TAG, "genDefaultAppInfo: 生成默认应用信息");
String branchName = "powerbell";
APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name));
@@ -594,39 +549,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
appInfo.setAppAPKName("PowerBell");
appInfo.setAppAPKFolderName("PowerBell");
LogUtils.d(TAG, "genDefaultAppInfo: end");
return appInfo;
}
// ======================== MainContentView 事件回调 ========================
@Override
public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: isChecked=" + isChecked);
sendRestartRemindThreadMessage();
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 充电提醒开关状态=" + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: isChecked=" + isChecked);
sendRestartRemindThreadMessage();
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 耗电提醒开关状态=" + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: isChecked=" + isChecked);
LogUtils.d(TAG, "onServiceSwitchChanged: 服务总开关状态=" + isChecked);
toggleServiceEnableState(isChecked);
}
@Override
public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: progress=" + progress);
sendRestartRemindThreadMessage();
LogUtils.d(TAG, "onChargeReminderProgressChanged: 充电提醒阈值=" + progress);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: progress=" + progress);
sendRestartRemindThreadMessage();
LogUtils.d(TAG, "onUsageReminderProgressChanged: 耗电提醒阈值=" + progress);
notifyServiceAppConfigChange();
}
}

View File

@@ -70,7 +70,7 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
@Override
public void onOHPCommit() {
mApplication.clearBatteryHistory();
sendBroadcast(new Intent(ControlCenterServiceReceiver.ACTION_UPDATE_SERVICENOTIFICATION));
sendBroadcast(new Intent(ControlCenterServiceReceiver.ACTION_UPDATE_FOREGROUND_NOTIFICATION));
initRecordText();
String szMSG = "The APP battery record is cleaned.";
LogUtils.d(TAG, szMSG);

View File

@@ -2,27 +2,38 @@ package cc.winboll.studio.powerbell.handlers;
import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import java.lang.ref.WeakReference;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:41
* @Describe 服务通信Handler:弱引用持有服务,避免内存泄漏,通知格式优化为 (+/-)(当前电量)(充电状态)
* @Date 2025/12/19 20:17
* @Describe 服务通信Handler
* 功能:处理电量提醒消息,构建并发送标准化通知
* 特性:弱引用防泄漏、参数严格校验、通知格式统一
* 适配Java7 | API30 | 小米手机
*/
public class ControlCenterServiceHandler extends Handler {
// ================================== 静态常量(置顶统一管理,清晰区分消息类型=================================
// ================================== 静态常量(置顶归类,消除魔法值=================================
public static final String TAG = "ControlCenterServiceHandler";
public static final int MSG_REMIND_TEXT = 1001; // 电量提醒消息+充电/-耗电)
public static final int MSG_REMIND_TEXT = 1001; // 电量提醒消息标识
// ================================== 成员变量(弱引用服务,杜绝内存泄漏)=================================
// 提醒类型常量
private static final String REMIND_TYPE_CHARGE = "+";
private static final String REMIND_TYPE_USAGE = "-";
// 电量范围常量
private static final int BATTERY_LEVEL_MIN = 0;
private static final int BATTERY_LEVEL_MAX = 100;
// ================================== 成员变量区弱引用防泄漏final保证不可变=================================
private final WeakReference<ControlCenterService> mwrControlCenterService;
// ================================== 构造方法(强制传入服务,初始化弱引用)=================================
public ControlCenterServiceHandler(ControlCenterService service) {
LogUtils.d(TAG, "初始化Handler,绑定服务实例:" + (service != null ? service.getClass().getSimpleName() : "null"));
LogUtils.d(TAG, "构造Handler | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
this.mwrControlCenterService = new WeakReference<>(service);
}
@@ -30,75 +41,73 @@ public class ControlCenterServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 解析线程传递的完整数据obj=提醒类型(+/-)arg1=当前电量arg2=充电状态(1=充电中,0=未充电)
// 解析消息参数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);
// 弱引用获取服务,避免持有强引用导致内存泄漏
LogUtils.d(TAG, "接收消息 | what=" + msg.what + " | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging);
// 弱引用获取服务,避免内存泄漏
ControlCenterService service = mwrControlCenterService.get();
if (service == null) {
LogUtils.e(TAG, "服务实例已回收,消息处理失败");
LogUtils.e(TAG, "服务实例已回收,终止消息处理");
return;
}
// 按消息类型分发处理,避免逻辑冗余
// 按消息类型分发处理
switch (msg.what) {
case MSG_REMIND_TEXT:
handleRemindMessage(service, remindType, currentBattery, isCharging);
break;
default:
LogUtils.w(TAG, "未知消息类型what" + msg.what);
LogUtils.w(TAG, "未知消息类型 | what=" + msg.what);
break;
}
}
// ================================== 业务辅助方法(重构通知内容,格式:(+/-)(当前电量)(充电状态)=================================
// ================================== 业务辅助方法(构建通知并发送,全链路参数校验=================================
/**
* 处理电量提醒消息,构建带电量+充电状态的通知模型
* @param service 服务实例(非空,已前置校验
* @param remindType 提醒类型(+充电提醒,-:耗电提醒
* @param currentBattery 当前电量0-100
* @param isCharging 充电状态true=充电中false=未充电)
* 处理电量提醒消息,构建带电量+充电状态的通知并发送
* @param service 控制中心服务实例(已校验非空
* @param remindType 提醒类型(+充电/-耗电
* @param currentBattery 当前电量0-100
* @param isCharging 充电状态
*/
private void handleRemindMessage(ControlCenterService service, String remindType, int currentBattery, boolean isCharging) {
LogUtils.d(TAG, "开始处理提醒消息,类型:" + remindType + ",电量:" + currentBattery + ",充电状态:" + isCharging);
LogUtils.d(TAG, "处理提醒消息 | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging);
// 1. 前置校验:通知工具类+提醒类型+电量有效性
// 1. 前置校验:通知工具类+参数有效性
if (service.getNotificationManager() == null) {
LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒");
return;
}
if (!"+".equals(remindType) && !"-".equals(remindType)) {
LogUtils.w(TAG, "无效提醒类型,跳过发送:" + remindType);
if (!REMIND_TYPE_CHARGE.equals(remindType) && !REMIND_TYPE_USAGE.equals(remindType)) {
LogUtils.w(TAG, "无效提醒类型 | type=" + remindType);
return;
}
if (currentBattery < 0 || currentBattery > 100) {
LogUtils.w(TAG, "无效当前电量,跳过发送:" + currentBattery);
if (currentBattery < BATTERY_LEVEL_MIN || currentBattery > BATTERY_LEVEL_MAX) {
LogUtils.w(TAG, "无效电量值 | battery=" + currentBattery + "需在0-100范围内");
return;
}
// 2. 构建通知模型,按格式拼接内容(核心优化)
// 2. 构建通知模型,使用String.format统一格式
NotificationMessage remindMsg = new NotificationMessage();
String chargeStateDesc = isCharging ? "充电中" : "未充电"; // 充电状态文字描述
if ("+".equals(remindType)) {
// 充电提醒:格式 (+)(当前电量)(充电状态)
String chargeStateDesc = isCharging ? "充电中" : "未充电";
if (REMIND_TYPE_CHARGE.equals(remindType)) {
remindMsg.setTitle("充电提醒");
remindMsg.setContent("(+) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已达标建议及时断电,保护电池寿命~");
remindMsg.setContent(String.format("(+) 当前电量%d%%%s已达标建议及时断电保护电池寿命", currentBattery, chargeStateDesc));
remindMsg.setRemindMSG("charge_remind");
LogUtils.d(TAG, "构建充电提醒通知,内容:" + remindMsg.getContent());
} else if ("-".equals(remindType)) {
// 耗电提醒:格式 (-)(当前电量)(充电状态)
} else {
remindMsg.setTitle("耗电提醒");
remindMsg.setContent("(-) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已偏低建议及时充电,避免设备关机~");
remindMsg.setContent(String.format("(-) 当前电量%d%%%s已偏低建议及时充电避免设备关机", currentBattery, chargeStateDesc));
remindMsg.setRemindMSG("usage_remind");
LogUtils.d(TAG, "构建耗电提醒通知,内容:" + remindMsg.getContent());
}
LogUtils.d(TAG, "构建通知完成 | title=" + remindMsg.getTitle() + " | content=" + remindMsg.getContent());
// 3. 调用服务工具类发送通知,复用现有逻辑
// 3. 调用工具类发送通知
service.getNotificationManager().showRemindNotification(service, remindMsg);
LogUtils.d(TAG, "提醒通知发送完成,标题:" + remindMsg.getTitle() + ",完整内容:" + remindMsg.getContent());
LogUtils.d(TAG, "提醒通知发送成功");
}
}

View File

@@ -14,34 +14,38 @@ import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import java.lang.ref.WeakReference;
/**
* 控制中心广播接收器
* 功能:监听电池状态变化、通知更新、线程启动指令
* 适配Java7 | API30 | 小米手机 | 内存泄漏防护
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/19 20:23
* @Describe 控制中心广播接收器
* 功能:监听电池状态变化、前台通知更新、配置变更指令
* 适配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 ACTION_UPDATE_FOREGROUND_NOTIFICATION = "cc.winboll.studio.powerbell.action.ACTION_UPDATE_SERVICE_FOREGROUND_NOTIFICATION";
public static final String ACTION_APPCONFIG_CHANGED = "cc.winboll.studio.powerbell.action.ACTION_START_REMIND__NOTIFICATION";
public static final String EXTRA_APP_CONFIG_BEAN = "extra_app_config_bean";
// 广播优先级常量
// 广播优先级与电量范围常量
private static final int BROADCAST_PRIORITY = IntentFilter.SYSTEM_HIGH_PRIORITY - 10;
private static final int BATTERY_LEVEL_MIN = 0;
private static final int BATTERY_LEVEL_MAX = 100;
// ================================== 成员变量区弱引用防泄漏volatile保线程安全=================================
private WeakReference<ControlCenterService> mwrControlCenterService;
private static volatile int sLastBatteryLevel = -1;
private static volatile boolean sIsCharging = false;
private static volatile int sLastBatteryLevel = -1; // 上次电量(多线程可见)
private static volatile boolean sIsCharging = false; // 上次充电状态(多线程可见)
// ================================== 构造方法(初始化弱引用,避免内存泄漏)=================================
// ================================== 构造方法(初始化弱引用,避免服务强引用泄漏)=================================
public ControlCenterServiceReceiver(ControlCenterService service) {
LogUtils.d(TAG, "constructor: 初始化广播接收器 | service=" + service);
LogUtils.d(TAG, "构造接收器 | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
this.mwrControlCenterService = new WeakReference<>(service);
}
// ================================== 广播核心接收逻辑入口方法分Action处理=================================
// ================================== 广播核心接收逻辑入口方法分Action分发处理)=================================
@Override
public void onReceive(Context context, Intent intent) {
LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null"));
@@ -63,14 +67,14 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
// 分Action处理业务逻辑
String action = intent.getAction();
switch (action) {
case ACTION_UPDATE_SERVICENOTIFICATION:
handleUpdateServiceNotification(service);
break;
case Intent.ACTION_BATTERY_CHANGED:
handleBatteryStateChanged(context, service, intent);
handleBatteryStateChanged(service, intent);
break;
case ACTION_START_REMINDTHREAD:
LogUtils.d(TAG, "onReceive: ACTION_START_REMINDTHREAD 逻辑待实现");
case ACTION_UPDATE_FOREGROUND_NOTIFICATION:
handleUpdateForegroundNotification(service);
break;
case ACTION_APPCONFIG_CHANGED:
handleNotifyAppConfigUpdate(service);
break;
default:
LogUtils.w(TAG, "onReceive: 未知Action=" + action);
@@ -79,44 +83,20 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
LogUtils.d(TAG, "onReceive: 广播处理完成");
}
// ================================== 业务逻辑方法(按功能拆分,强化容错)=================================
/**
* 处理前台服务通知更新
* @param service 控制中心服务实例
*/
private void handleUpdateServiceNotification(ControlCenterService service) {
LogUtils.d(TAG, "handleUpdateServiceNotification: 执行通知更新 | service=" + service);
try {
NotificationManagerUtils notifyUtils = service.getNotificationManager();
NotificationMessage notifyMsg = service.getForegroundNotifyMsg();
// 非空校验+兜底重建
if (notifyUtils == null || notifyMsg == null) {
LogUtils.e(TAG, "handleUpdateServiceNotification: 通知工具类或消息为空");
return;
}
notifyUtils.updateForegroundServiceNotify(notifyMsg);
LogUtils.d(TAG, "handleUpdateServiceNotification: 通知更新成功");
} catch (Exception e) {
LogUtils.e(TAG, "handleUpdateServiceNotification: 通知更新失败", e);
}
}
// ================================== 业务处理方法(按功能拆分,强化容错与日志=================================
/**
* 处理电池状态变化广播
* @param context 上下文
* @param service 控制中心服务实例
* @param intent 广播意图
* @param intent 电池状态广播意图
*/
private void handleBatteryStateChanged(Context context, ControlCenterService service, Intent intent) {
LogUtils.d(TAG, "handleBatteryStateChanged: 处理电池状态变化 | context=" + context + " | service=" + service);
private void handleBatteryStateChanged(ControlCenterService service, Intent intent) {
LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | service=" + service);
try {
// 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);
// 1. 解析并校验当前电池状态
boolean currentCharging = BatteryUtils.isCharging(intent);
int currentBatteryLevel = BatteryUtils.getCurrentBatteryLevel(intent);
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
LogUtils.d(TAG, "handleBatteryStateChanged: 当前状态 | 充电=" + currentCharging + " | 电量=" + currentBatteryLevel + "%");
// 2. 状态无变化则跳过,减少无效运算
if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) {
@@ -124,8 +104,8 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
return;
}
// 3. 加载最新配置(级兜底)
AppConfigBean latestConfig = loadLatestConfig(context);
// 3. 加载最新配置(级兜底:本地配置→服务内存配置→默认配置
AppConfigBean latestConfig = loadLatestConfig(service);
if (latestConfig == null) {
latestConfig = service.getCurrentConfigBean();
if (latestConfig == null) {
@@ -134,29 +114,80 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
}
}
// 4. 同步电池状态到配置,更新服务与线程
// 4. 同步电池状态到配置,通知服务更新线程
latestConfig.setCurrentBatteryValue(currentBatteryLevel);
latestConfig.setIsCharging(currentCharging);
service.notifyAppConfigUpdate(latestConfig);
// 5. 缓存最新状态,保多线程可见
// 5. 更新静态缓存状态,保多线程可见
sIsCharging = currentCharging;
sLastBatteryLevel = currentBatteryLevel;
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功");
} catch (Exception e) {
LogUtils.e(TAG, "handleBatteryStateChanged: 电池状态处理失败", e);
LogUtils.e(TAG, "handleBatteryStateChanged: 处理失败", e);
}
}
// ================================== 内部辅助方法(拆分通用逻辑,统一管理)=================================
/**
* 处理配置变更通知,同步缓存状态到配置
* @param service 控制中心服务实例
*/
private void handleNotifyAppConfigUpdate(ControlCenterService service) {
LogUtils.d(TAG, "handleNotifyAppConfigUpdate: 同步缓存状态到配置 | service=" + service);
try {
// 加载最新配置(三级兜底)
AppConfigBean latestConfig = loadLatestConfig(service);
if (latestConfig == null) {
latestConfig = service.getCurrentConfigBean();
if (latestConfig == null) {
latestConfig = new AppConfigBean();
LogUtils.w(TAG, "handleNotifyAppConfigUpdate: 配置为空,使用默认配置");
}
}
// 同步缓存的电池状态到配置
latestConfig.setCurrentBatteryValue(sLastBatteryLevel);
latestConfig.setIsCharging(sIsCharging);
service.notifyAppConfigUpdate(latestConfig);
LogUtils.d(TAG, "handleNotifyAppConfigUpdate: 配置同步成功 | 缓存电量=" + sLastBatteryLevel + "% | 充电状态=" + sIsCharging);
} catch (Exception e) {
LogUtils.e(TAG, "handleNotifyAppConfigUpdate: 处理失败", e);
}
}
/**
* 处理前台服务通知更新
* @param service 控制中心服务实例
*/
private void handleUpdateForegroundNotification(ControlCenterService service) {
LogUtils.d(TAG, "handleUpdateForegroundNotification: 更新前台通知 | service=" + service);
try {
NotificationManagerUtils notifyUtils = service.getNotificationManager();
NotificationMessage notifyMsg = service.getForegroundNotifyMsg();
// 非空校验,避免空指针
if (notifyUtils == null || notifyMsg == null) {
LogUtils.e(TAG, "handleUpdateForegroundNotification: 通知工具类或消息为空");
return;
}
notifyUtils.updateForegroundServiceNotify(notifyMsg);
LogUtils.d(TAG, "handleUpdateForegroundNotification: 前台通知更新成功");
} catch (Exception e) {
LogUtils.e(TAG, "handleUpdateForegroundNotification: 处理失败", e);
}
}
// ================================== 内部辅助方法(通用逻辑拆分,统一管理)=================================
/**
* 加载最新应用配置
* @param context 上下文
* @return 最新配置实例失败返回null
*/
private AppConfigBean loadLatestConfig(Context context) {
LogUtils.d(TAG, "loadLatestConfig: 加载最新配置 | context=" + context);
LogUtils.d(TAG, "loadLatestConfig: 读取本地配置 | context=" + context);
try {
if (context == null) {
LogUtils.e(TAG, "loadLatestConfig: 上下文为空");
@@ -170,10 +201,10 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
}
configUtils.reloadAllConfig();
LogUtils.d(TAG, "loadLatestConfig: 配置加载成功");
LogUtils.d(TAG, "loadLatestConfig: 本地配置加载成功");
return configUtils.mAppConfigBean;
} catch (Exception e) {
LogUtils.e(TAG, "loadLatestConfig: 配置加载失败", e);
LogUtils.e(TAG, "loadLatestConfig: 加载失败", e);
return null;
}
}
@@ -184,7 +215,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
* @param context 上下文
*/
public void registerAction(Context context) {
LogUtils.d(TAG, "registerAction: 注册广播 | context=" + context);
LogUtils.d(TAG, "registerAction: 注册广播接收器 | context=" + context);
if (context == null) {
LogUtils.e(TAG, "registerAction: 上下文为空,注册失败");
return;
@@ -195,15 +226,15 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
unregisterAction(context);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_UPDATE_SERVICENOTIFICATION);
filter.addAction(ACTION_START_REMINDTHREAD);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_UPDATE_FOREGROUND_NOTIFICATION);
filter.addAction(ACTION_APPCONFIG_CHANGED);
filter.setPriority(BROADCAST_PRIORITY);
context.registerReceiver(this, filter);
LogUtils.d(TAG, "registerAction: 广播注册成功");
} catch (Exception e) {
LogUtils.e(TAG, "registerAction: 广播注册失败", e);
LogUtils.e(TAG, "registerAction: 注册失败", e);
}
}
@@ -212,7 +243,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
* @param context 上下文
*/
public void unregisterAction(Context context) {
LogUtils.d(TAG, "unregisterAction: 注销广播 | context=" + context);
LogUtils.d(TAG, "unregisterAction: 注销广播接收器 | context=" + context);
if (context == null) {
LogUtils.e(TAG, "unregisterAction: 上下文为空,注销失败");
return;
@@ -224,7 +255,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
} catch (IllegalArgumentException e) {
LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销");
} catch (Exception e) {
LogUtils.e(TAG, "unregisterAction: 广播注销失败", e);
LogUtils.e(TAG, "unregisterAction: 注销失败", e);
}
}
@@ -234,7 +265,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
*/
public void release() {
LogUtils.d(TAG, "release: 释放广播接收器资源");
// 清空弱引用
// 清空弱引用帮助GC回收
if (mwrControlCenterService != null) {
mwrControlCenterService.clear();
mwrControlCenterService = null;

View File

@@ -10,35 +10,49 @@ import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BatteryUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/19 20:13
* @Describe 全局应用广播接收器
* 功能:监听系统电池状态变化,同步状态到配置工具类,通知页面更新
* 适配Java7 | API30 | 内存泄漏防护
*/
public class GlobalApplicationReceiver extends BroadcastReceiver {
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = "GlobalApplicationReceiver";
private static final int BATTERY_LEVEL_MIN = 0;
private static final int BATTERY_LEVEL_MAX = 100;
private AppConfigUtils mAppConfigUtils;
// ================================== 静态成员变量线程安全volatile保证多线程可见性=================================
private static volatile int sLastBatteryLevel = -1; // 历史电量0-100
private static volatile boolean sLastIsCharging = false; // 历史充电状态
// ================================== 成员变量区(按功能分层)=================================
private App mGlobalApplication;
// 存储历史电池状态,用于判断变化(优化命名,明确语义)
private static volatile int sLastBatteryLevel = -1; // 历史电量0-100
private static volatile boolean sLastIsCharging = false; // 历史充电状态
// 当前Receiver实例优化命名避免歧义
private AppConfigUtils mAppConfigUtils;
private GlobalApplicationReceiver mCurrentReceiver;
// 构造方法(强化参数校验,避免空指针)
// ================================== 构造方法(强化参数校验,初始化核心依赖)=================================
public GlobalApplicationReceiver(App globalApplication) {
LogUtils.d(TAG, "构造接收器 | App=" + globalApplication);
if (globalApplication == null) {
LogUtils.e(TAG, "GlobalApplicationReceiver: App instance is null");
LogUtils.e(TAG, "构造失败App实例为空");
throw new IllegalArgumentException("App cannot be null");
}
this.mCurrentReceiver = this;
this.mGlobalApplication = globalApplication;
this.mAppConfigUtils = App.getAppConfigUtils(mGlobalApplication);
LogUtils.d(TAG, "构造完成AppConfigUtils=" + mAppConfigUtils);
}
// ================================== 广播核心接收逻辑(入口方法,过滤电池状态广播)=================================
@Override
public void onReceive(Context context, Intent intent) {
LogUtils.d(TAG, "onReceive: enter, action=" + intent.getAction());
// 双重空指针防护context/intent/action 均校验)
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 (context/intent is null)");
LogUtils.e(TAG, "onReceive: 参数无效,终止处理");
return;
}
@@ -46,99 +60,119 @@ public class GlobalApplicationReceiver extends BroadcastReceiver {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
handleBatteryStateChanged(context, intent);
}
LogUtils.d(TAG, "onReceive: exit");
LogUtils.d(TAG, "onReceive: 广播处理完成");
}
// ================================== 业务逻辑方法(处理电池状态变化,同步配置+通知页面)=================================
/**
* 处理电池状态变化(核心逻辑:复用 BatteryUtils优化状态同步
* 处理电池状态变化广播
* @param context 上下文
* @param intent 电池状态广播意图
*/
private void handleBatteryStateChanged(Context context, Intent intent) {
// 1. 用 BatteryUtils 解析当前电池状态(复用工具类,避免重复代码)
boolean currentIsCharging = BatteryUtils.isCharging(context); // 调用工具类判断充电状态
int currentBatteryLevel = BatteryUtils.getCurrentBattery(context); // 调用工具类获取电量0-100
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, 0), 100); // 二次校验,确保范围有效
LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | intent=" + intent);
// 1. 解析当前电池状态(复用工具类,二次校验电量范围)
boolean currentIsCharging = BatteryUtils.isCharging(intent);
int currentBatteryLevel = BatteryUtils.getCurrentBatteryLevel(intent);
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
LogUtils.d(TAG, "handleBatteryStateChanged: 当前状态 | 充电=" + currentIsCharging + " | 电量=" + currentBatteryLevel + "%");
LogUtils.d(TAG, "handleBatteryStateChanged: current - charging=" + currentIsCharging + ", level=" + currentBatteryLevel);
// 2. 状态无变化,直接跳过(避免无效运算)
// 2. 状态无变化则跳过,减少无效运算
if (currentIsCharging == sLastIsCharging && currentBatteryLevel == sLastBatteryLevel) {
LogUtils.d(TAG, "handleBatteryStateChanged: no state change, skip");
LogUtils.d(TAG, "handleBatteryStateChanged: 状态无变化,跳过处理");
return;
}
// 3. 同步最新状态到配置工具类(确保配置实时更新)
// 3. 同步最新状态到配置工具类
if (mAppConfigUtils != null) {
if (currentIsCharging != sLastIsCharging) {
mAppConfigUtils.setCharging(currentIsCharging); // 同步充电状态
mAppConfigUtils.setCharging(currentIsCharging);
LogUtils.d(TAG, "handleBatteryStateChanged: 同步充电状态 | " + currentIsCharging);
}
if (currentBatteryLevel != sLastBatteryLevel) {
mAppConfigUtils.setCurrentBatteryValue(currentBatteryLevel); // 同步当前电量
mAppConfigUtils.setCurrentBatteryValue(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 同步电量 | " + currentBatteryLevel + "%");
}
} else {
LogUtils.e(TAG, "handleBatteryStateChanged: AppConfigUtils is null, sync failed");
LogUtils.e(TAG, "handleBatteryStateChanged: AppConfigUtils为空,同步失败");
}
// 4. 电池状态变化后的业务逻辑(保留原有逻辑,强化空指针防护)
// 取消旧提醒(若后续需要启用,可调用 NotificationHelper.cancelRemindNotification(context)
// 4. 执行状态变化后的业务逻辑
// 记录电量变化时间
if (App.getAppCacheUtils(context) != null) {
App.getAppCacheUtils(context).addChangingTime(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 记录电量变化时间");
}
// 发送电量更新消息到MainActivity
// 通知MainActivity更新电量
MainActivity.sendCurrentBatteryValueMessage(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 发送电量更新消息到MainActivity");
// 5. 更新历史状态缓存volatile 保证多线程可见性)
// 5. 更新历史状态缓存
sLastIsCharging = currentIsCharging;
sLastBatteryLevel = currentBatteryLevel;
LogUtils.d(TAG, "handleBatteryStateChanged: sync success, update last state");
LogUtils.d(TAG, "handleBatteryStateChanged: 更新历史状态完成");
}
// 注册广播(优化容错,避免重复注册)
// ================================== 广播注册/注销(强化容错,避免重复操作)=================================
/**
* 注册广播接收器
*/
public void registerAction() {
LogUtils.d(TAG, "registerAction: 注册广播");
if (mGlobalApplication == null || mCurrentReceiver == null) {
LogUtils.e(TAG, "registerAction: App/receiver is null, register failed");
LogUtils.e(TAG, "注册失败:App或Receiver实例为空");
return;
}
try {
// 先注销再注册,避免重复注册导致异常
// 先注销再注册,避免重复注册异常
unregisterAction();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
mGlobalApplication.registerReceiver(mCurrentReceiver, filter);
LogUtils.d(TAG, "registerAction: broadcast receiver registered success");
LogUtils.d(TAG, "registerAction: 广播注册成功");
} catch (Exception e) {
LogUtils.e(TAG, "registerAction: register failed", e);
LogUtils.e(TAG, "registerAction: 注册失败", e);
}
}
// 新增:注销广播(避免内存泄漏,供外部调用)
/**
* 注销广播接收器
*/
public void unregisterAction() {
LogUtils.d(TAG, "unregisterAction: 注销广播");
if (mGlobalApplication == null || mCurrentReceiver == null) {
LogUtils.e(TAG, "unregisterAction: App/receiver is null, unregister failed");
LogUtils.e(TAG, "注销失败:App或Receiver实例为空");
return;
}
try {
mGlobalApplication.unregisterReceiver(mCurrentReceiver);
LogUtils.d(TAG, "unregisterAction: broadcast receiver unregistered success");
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: unregister failed", e);
LogUtils.e(TAG, "unregisterAction: 注销失败", e);
}
}
// 新增主动释放资源供App销毁时调用彻底防泄漏
// ================================== 资源释放方法(主动释放,彻底避免内存泄漏)=================================
/**
* 释放接收器资源供App销毁时调用
*/
public void release() {
LogUtils.d(TAG, "release: receiver release resources");
LogUtils.d(TAG, "release: 释放接收器资源");
// 注销广播
unregisterAction();
// 置空引用帮助GC回收
mGlobalApplication = null;
mAppConfigUtils = null;
mCurrentReceiver = null;
// 重置静态缓存
// 重置静态状态缓存
sLastBatteryLevel = -1;
sLastIsCharging = false;
LogUtils.d(TAG, "release: 资源释放完成");
}
}

View File

@@ -21,22 +21,24 @@ import java.io.Serializable;
import java.util.List;
/**
* 电池提醒核心服务
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/19 20:21
* @Describe 电池提醒核心服务
* 功能:管理前台服务生命周期、控制提醒线程启停、处理配置更新
* 适配Java7 | API30 | 前台服务超时防护 | 电池优化忽略引导
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 15:48
*/
public class ControlCenterService extends Service {
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = "ControlCenterService";
// 服务指令常量(带包名前缀防冲突)
// 服务指令Action常量(带包名前缀防冲突)
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;
// 服务状态标记常量
private static final int SERVICE_RETURN_STICKY = START_STICKY;
// ================================== 成员变量区按功能分层volatile保证多线程可见性=================================
// 服务控制配置
@@ -46,11 +48,11 @@ public class ControlCenterService extends Service {
private NotificationManagerUtils mNotificationManager;
private AppConfigBean mCurrentConfigBean;
private NotificationMessage mForegroundNotifyMsg;
// 服务状态标记
// 服务状态标记volatile保证多线程可见性
private static volatile boolean isServiceRunning;
private static volatile boolean mIsDestroyed;
// ================================== 服务生命周期方法(按执行顺序排列)=================================
// ================================== 服务生命周期方法(按执行顺序排列onCreate→onStartCommand→onBind→onDestroy=================================
@Override
public void onCreate() {
super.onCreate();
@@ -68,19 +70,25 @@ public class ControlCenterService extends Service {
runCoreServiceLogic();
int returnFlag = (mServiceControlBean != null && mServiceControlBean.isEnableService())
? START_STICKY
? SERVICE_RETURN_STICKY
: super.onStartCommand(intent, flags, startId);
LogUtils.d(TAG, "onStartCommand: 处理完成 | 返回策略=" + (returnFlag == START_STICKY ? "START_STICKY" : "DEFAULT"));
LogUtils.d(TAG, "onStartCommand: 处理完成 | 返回策略=" + (returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
return returnFlag;
}
@Override
public IBinder onBind(Intent intent) {
LogUtils.d(TAG, "onBind: 绑定请求 | intent=" + intent);
return null;
}
@Override
public void onDestroy() {
LogUtils.d(TAG, "onDestroy: 服务销毁流程启动");
super.onDestroy();
// 资源释放顺序:前台服务 → 线程 → Handler → 通知 → 引用
// 资源释放顺序:前台服务 → 线程 → Handler → 通知 → 引用(避免内存泄漏)
stopForegroundService();
RemindThread.stopRemindThreadSafely();
destroyHandler();
@@ -97,12 +105,6 @@ public class ControlCenterService extends Service {
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
}
@Override
public IBinder onBind(Intent intent) {
LogUtils.d(TAG, "onBind: 绑定请求 | intent=" + intent);
return null;
}
// ================================== 核心业务逻辑(独立抽取,统一调用)=================================
/**
* 服务核心运行逻辑在onCreate/onStartCommand复用
@@ -133,7 +135,7 @@ public class ControlCenterService extends Service {
}
}
// ================================== 前台通知管理优先执行防止5秒超时=================================
// ================================== 前台通知管理(优先执行,防止API26+前台服务5秒超时=================================
/**
* 立即初始化前台通知防止API26+前台服务超时异常
* @return true=成功 false=失败
@@ -210,7 +212,7 @@ public class ControlCenterService extends Service {
}
}
// ================================== 业务组件初始化与销毁=================================
// ================================== 业务组件初始化与销毁Handler/线程等)=================================
/**
* 初始化Handler等核心业务组件
*/
@@ -312,7 +314,7 @@ public class ControlCenterService extends Service {
/**
* 外部更新配置并触发线程重启
* @param context 上下文
* @param context 上下文
* @param configBean 新配置
*/
public static void updateStatus(Context context, AppConfigBean configBean) {

View File

@@ -8,10 +8,11 @@ import cc.winboll.studio.powerbell.models.AppConfigBean;
import java.lang.ref.WeakReference;
/**
* 提醒线程(单例模式)
* 功能:统一管理充电/耗电提醒逻辑,发送提醒时携带当前电量+充电状态
* 适配Java7 | API30 | 小米手机
* 特性:线程安全、内存泄漏防护、配置参数校验
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/19 20:28
* @Describe 提醒线程(线程安全单例)
* 功能:管理充电/耗电提醒逻辑触发条件时向Handler发送提醒消息
* 适配Java7 | API30 | 内存泄漏防护 | 多线程状态同步
* 对外接口:{@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)}、{@link #stopRemindThreadSafely()}
*/
public class RemindThread extends Thread {
@@ -26,19 +27,19 @@ public class RemindThread extends Thread {
// 状态常量
private static final int INVALID_BATTERY_VALUE = -1;
// ================================== 单例核心(线程安全,双重校验锁)=================================
// ================================== 单例核心(双重校验锁,保证线程安全=================================
private static volatile RemindThread sInstance;
// ================================== 成员变量区按功能分层volatile保证多线程可见性=================================
// 弱引用依赖(防内存泄漏)
// 弱引用依赖(防内存泄漏ApplicationContext 避免 Activity 引用
private Context mContext;
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
// 线程状态标记
// 线程状态标记volatile 确保多线程可见)
private volatile boolean isExist;
private volatile boolean isReminding;
// 业务配置参数
// 业务配置参数volatile 确保配置变更实时生效)
private volatile boolean isEnableChargeReminder;
private volatile boolean isEnableUsageReminder;
private volatile long sleepTime;
@@ -47,60 +48,57 @@ public class RemindThread extends Thread {
private volatile int quantityOfElectricity;
private volatile boolean isCharging;
// 并发安全锁
// 并发安全锁(保护线程状态变更)
private final Object mLock = new Object();
// ================================== 私有构造器(单例专用,禁止外部实例化)=================================
private RemindThread(Context context, ControlCenterServiceHandler handler) {
LogUtils.d(TAG, "构造线程实例 | threadName=" + getName() + " | threadId=" + getId());
LogUtils.d(TAG, "创建线程实例 | threadId=" + getId() + " | threadName=" + getName());
this.mContext = context.getApplicationContext();
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
resetThreadStateInternal();
}
// ================================== 单例获取方法(核心,统一管理单例创建=================================
// ================================== 单例获取方法(核心,双重校验锁=================================
/**
* 私有单例获取方法,双重校验锁保证线程安全
* @param context 上下文
* @param handler 服务处理器
* 获取单例实例,保证全局唯一
* @param context 上下文使用ApplicationContext
* @param handler 服务处理器
* @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());
LogUtils.d(TAG, "单例创建成功 | threadId=" + sInstance.getId());
}
}
}
return sInstance;
}
// ================================== 对外公开静态接口(全部基于单例实现=================================
// ================================== 对外公开静态接口(基于单例,统一线程管理=================================
/**
* 启动提醒线程(基于单例操作,确保全局唯一)
* 启动提醒线程,同步最新配置
* @param context 上下文(非空)
* @param handler 服务处理器(非空)
* @param config 应用配置Bean非空
* @return true: isReminding为真/线程启动成功false: 入参非法/启动失败
* @return true: 启动成功/已在运行false: 入参非法
*/
public static boolean startRemindThread(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
LogUtils.d(TAG, "startRemindThread: 调用 | context=" + context + " | handler=" + handler + " | config=" + config);
// 入参校验
LogUtils.d(TAG, "请求启动线程 | context=" + context + " | handler=" + handler + " | config=" + config);
// 入参严格校验
if (context == null || handler == null || config == null) {
LogUtils.e(TAG, "startRemindThread: 入参为空,启动失败");
LogUtils.e(TAG, "启动失败:入参为空");
return false;
}
// 获取单例
RemindThread instance = getInstance(context, handler);
// 已在提醒状态,同步配置后返回
// 已在提醒状态,仅同步配置
if (instance.isReminding) {
instance.setAppConfigBean(config);
LogUtils.d(TAG, "startRemindThread: 线程已在提醒状态,同步最新配置 | threadId=" + instance.getId());
LogUtils.d(TAG, "线程已在运行,同步最新配置 | threadId=" + instance.getId());
return true;
}
@@ -109,28 +107,28 @@ public class RemindThread extends Thread {
if (!instance.isRunning()) {
instance.isExist = false;
instance.start();
LogUtils.d(TAG, "startRemindThread: 线程启动成功 | threadId=" + instance.getId());
LogUtils.d(TAG, "线程启动成功 | threadId=" + instance.getId());
return true;
} else {
LogUtils.d(TAG, "startRemindThread: 线程已在运行 | threadId=" + instance.getId());
LogUtils.d(TAG, "线程已在运行状态 | threadId=" + instance.getId());
return false;
}
}
/**
* 安全停止线程(基于单例操作,优雅销毁唯一实例)
* 安全停止线程,优雅销毁单例
*/
public static void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely: 调用 | sInstance=" + (sInstance != null));
LogUtils.d(TAG, "请求安全停止线程 | 单例存在=" + (sInstance != null));
synchronized (RemindThread.class) {
if (sInstance == null) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程实例为空,无需停止");
LogUtils.w(TAG, "停止失败:线程实例为空");
return;
}
// 线程未运行,直接销毁
if (!sInstance.isRunning()) {
LogUtils.d(TAG, "stopRemindThreadSafely: 线程未运行,直接销毁 | threadId=" + sInstance.getId());
LogUtils.d(TAG, "线程未运行,直接销毁 | threadId=" + sInstance.getId());
destroyInstance();
return;
}
@@ -138,41 +136,39 @@ public class RemindThread extends Thread {
// 标记退出,等待线程自然结束
sInstance.isExist = true;
sInstance.isReminding = false;
LogUtils.d(TAG, "stopRemindThreadSafely: 标记线程退出 | threadId=" + sInstance.getId());
LogUtils.d(TAG, "标记线程退出,等待结束 | threadId=" + sInstance.getId());
try {
sInstance.join(THREAD_JOIN_TIMEOUT);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.e(TAG, "stopRemindThreadSafely: 等待线程退出被中断", e);
LogUtils.e(TAG, "等待线程退出被中断", e);
}
// 销毁单例
// 销毁单例释放资源
destroyInstance();
LogUtils.d(TAG, "stopRemindThreadSafely: 线程安全销毁完成");
LogUtils.d(TAG, "线程安全销毁完成");
}
}
// ================================== 私有单例管理方法=================================
/**
* 销毁单例,安全释放资源
* 销毁单例,释放所有资源
*/
private static void destroyInstance() {
LogUtils.d(TAG, "destroyInstance: 开始销毁单例 | sInstance=" + (sInstance != null));
synchronized (RemindThread.class) {
if (sInstance != null) {
// 终止线程并释放资源
sInstance.isExist = true;
sInstance.isReminding = false;
// 中断存活线程
if (sInstance.isAlive()) {
sInstance.interrupt();
LogUtils.d(TAG, "destroyInstance: 线程已中断 | threadId=" + sInstance.getId());
LogUtils.d(TAG, "中断存活线程 | threadId=" + sInstance.getId());
}
// 释放线程内部资源
sInstance.releaseResourcesInternal();
sInstance = null;
LogUtils.d(TAG, "destroyInstance: 单例销毁完成");
} else {
LogUtils.w(TAG, "destroyInstance: 单例已为空,跳过销毁");
LogUtils.d(TAG, "单例销毁完成");
}
}
}
@@ -180,74 +176,73 @@ public class RemindThread extends Thread {
// ================================== 线程核心运行逻辑=================================
@Override
public void run() {
LogUtils.d(TAG, "run: 线程启动 | threadId=" + Thread.currentThread().getId() + " | state=" + getState());
LogUtils.d(TAG, "线程进入运行 | threadId=" + getId() + " | 状态=" + getState());
// 初始化提醒状态(加锁保护)
// 初始化提醒状态(加锁保护,避免多线程竞争
synchronized (mLock) {
if (!isExist && !isReminding) {
isReminding = true;
LogUtils.d(TAG, "run: 初始化提醒状态成功 | isReminding=true");
LogUtils.d(TAG, "提醒状态初始化成功 | isReminding=true");
} else {
LogUtils.d(TAG, "run: 线程退出条件满足 | isExist=" + isExist + " | isReminding=" + isReminding);
LogUtils.d(TAG, "线程退出条件满足 | isExist=" + isExist + " | isReminding=" + isReminding);
cleanThreadStateInternal();
return;
}
}
// 核心检测循环
LogUtils.d(TAG, "run: 进入电量检测循环 | sleepTime=" + sleepTime + "ms");
// 核心电量检测循环
LogUtils.d(TAG, "进入电量检测循环 | 休眠时间=" + sleepTime + "ms");
while (!isExist) {
try {
// 快速退出判断
if (isExist) break;
// 电量有效性校验
// 电量有效性校验非0-100视为无效
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
LogUtils.w(TAG, "run: 电量无效,退出循环 | currentBattery=" + quantityOfElectricity);
LogUtils.w(TAG, "电量无效,退出循环 | 当前电量=" + quantityOfElectricity);
break;
}
// 充电提醒触发逻辑
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "run: 触发充电提醒 | battery=" + quantityOfElectricity + "threshold=" + chargeReminderValue);
LogUtils.d(TAG, "触发充电提醒 | 当前电量=" + quantityOfElectricity + "阈值=" + chargeReminderValue);
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
} else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "run: 触发耗电提醒 | battery=" + quantityOfElectricity + "threshold=" + usageReminderValue);
LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + "阈值=" + usageReminderValue);
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
}
// 安全休眠
// 安全休眠,保留中断标记
safeSleepInternal(sleepTime);
} catch (Exception e) {
LogUtils.e(TAG, "run: 线程运行异常,休眠重试", e);
LogUtils.e(TAG, "循环运行异常,休眠重试", e);
safeSleepInternal(sleepTime);
}
}
// 循环退出,清理状态
cleanThreadStateInternal();
LogUtils.d(TAG, "run: 线程循环退出 | threadId=" + Thread.currentThread().getId());
LogUtils.d(TAG, "线程运行结束 | threadId=" + getId());
}
// ================================== 内部业务辅助方法=================================
/**
* 发送提醒消息内部方法弱引用Handler防泄漏)
* 发送提醒消息到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);
// 前置校验
// 前置状态校验
if (isExist || !isReminding) {
LogUtils.d(TAG, "sendNotificationMessageInternal: 线程退出或提醒关闭,跳过发送");
LogUtils.d(TAG, "消息发送跳过:线程退出或提醒关闭");
return;
}
// 获取Handler并发送消息
// 获取弱引用的Handler
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler.get();
if (handler == null) {
LogUtils.w(TAG, "sendNotificationMessageInternal: Handler已回收,发送失败");
LogUtils.w(TAG, "消息发送失败:Handler已回收");
return;
}
@@ -258,23 +253,26 @@ public class RemindThread extends Thread {
try {
handler.sendMessage(message);
LogUtils.d(TAG, "sendNotificationMessageInternal: 提醒消息发送成功");
LogUtils.d(TAG, "提醒消息发送成功 | 类型=" + type + " | 电量=" + battery);
} catch (Exception e) {
LogUtils.e(TAG, "sendNotificationMessageInternal: 消息发送异常", e);
if (message != null) message.recycle();
LogUtils.e(TAG, "消息发送异常", e);
// 异常时回收Message避免内存泄漏
if (message != null) {
message.recycle();
}
}
}
/**
* 安全休眠(保留中断标记,确保线程可退出)
* @param millis 休眠时长
* 安全休眠,响应线程中断
* @param millis 休眠时长(ms)
*/
private void safeSleepInternal(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.w(TAG, "safeSleepInternal: 休眠被中断,线程准备退出");
LogUtils.w(TAG, "休眠被中断,线程准备退出");
}
}
@@ -282,11 +280,11 @@ public class RemindThread extends Thread {
* 重置线程初始状态(构造器专用)
*/
private void resetThreadStateInternal() {
LogUtils.d(TAG, "resetThreadStateInternal: 重置线程初始状态");
// 状态标记
LogUtils.d(TAG, "重置线程初始状态");
// 状态标记初始化
isExist = false;
isReminding = false;
// 配置参数
// 配置参数初始化
isEnableChargeReminder = false;
isEnableUsageReminder = false;
sleepTime = DEFAULT_SLEEP_TIME;
@@ -297,31 +295,32 @@ public class RemindThread extends Thread {
}
/**
* 清理线程运行状态(退出循环专用)
* 清理线程运行状态(循环退出时调用)
*/
private void cleanThreadStateInternal() {
LogUtils.d(TAG, "cleanThreadStateInternal: 清理线程运行状态");
LogUtils.d(TAG, "清理线程运行状态");
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, "同步应用配置 | config=" + config);
if (config == null) {
LogUtils.e(TAG, "setAppConfigBean: 配置Bean为空,同步失败");
LogUtils.e(TAG, "配置同步失败:配置Bean为空");
quantityOfElectricity = INVALID_BATTERY_VALUE;
return;
}
// 配置参数同步+范围校验
// 配置参数同步 + 范围校验(确保参数合法)
isEnableChargeReminder = config.isEnableChargeReminder();
isEnableUsageReminder = config.isEnableUsageReminder();
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
@@ -332,19 +331,22 @@ public class RemindThread extends Thread {
isCharging = config.isCharging();
isReminding = isEnableChargeReminder || isEnableUsageReminder;
LogUtils.d(TAG, "setAppConfigBean: 配置同步完成 | sleepTime=" + sleepTime + "ms | isReminding=" + isReminding + " | currentBattery=" + quantityOfElectricity);
LogUtils.d(TAG, "配置同步完成 | 休眠时间=" + sleepTime + "ms | 提醒开启=" + isReminding + " | 当前电量=" + quantityOfElectricity);
}
/**
* 释放线程资源(内部方法,防内存泄漏
* 释放线程内部资源,杜绝内存泄漏
*/
private void releaseResourcesInternal() {
LogUtils.d(TAG, "releaseResourcesInternal: 释放线程资源");
LogUtils.d(TAG, "释放线程内部资源");
// 释放上下文引用
mContext = null;
// 清空WeakReference
if (mwrControlCenterServiceHandler != null) {
mwrControlCenterServiceHandler.clear();
mwrControlCenterServiceHandler = null;
}
// 清理线程状态
cleanThreadStateInternal();
}
@@ -354,13 +356,13 @@ public class RemindThread extends Thread {
*/
private boolean isRunning() {
boolean running = !isExist && isAlive();
LogUtils.d(TAG, "isRunning: 线程运行状态=" + running + " | isExist=" + isExist + " | isAlive=" + isAlive());
LogUtils.d(TAG, "线程运行状态判断 | 运行中=" + running + " | 退出标记=" + isExist + " | 存活=" + isAlive());
return running;
}
// ================================== Getter/Setter按需开放=================================
public void setIsExist(boolean isExist) {
LogUtils.d(TAG, "setIsExist: 调用 | isExist=" + isExist);
LogUtils.d(TAG, "设置线程退出标记 | isExist=" + isExist);
this.isExist = isExist;
}