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

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

View File

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

View File

@@ -2,27 +2,38 @@ package cc.winboll.studio.powerbell.handlers;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import java.lang.ref.WeakReference;
import cc.winboll.studio.libappbase.LogUtils; 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.models.NotificationMessage;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import java.lang.ref.WeakReference;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:41 * @Date 2025/12/19 20:17
* @Describe 服务通信Handler:弱引用持有服务,避免内存泄漏,通知格式优化为 (+/-)(当前电量)(充电状态) * @Describe 服务通信Handler
* 功能:处理电量提醒消息,构建并发送标准化通知
* 特性:弱引用防泄漏、参数严格校验、通知格式统一
* 适配Java7 | API30 | 小米手机
*/ */
public class ControlCenterServiceHandler extends Handler { public class ControlCenterServiceHandler extends Handler {
// ================================== 静态常量(置顶统一管理,清晰区分消息类型================================= // ================================== 静态常量(置顶归类,消除魔法值=================================
public static final String TAG = "ControlCenterServiceHandler"; 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; private final WeakReference<ControlCenterService> mwrControlCenterService;
// ================================== 构造方法(强制传入服务,初始化弱引用)================================= // ================================== 构造方法(强制传入服务,初始化弱引用)=================================
public ControlCenterServiceHandler(ControlCenterService service) { 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); this.mwrControlCenterService = new WeakReference<>(service);
} }
@@ -30,75 +41,73 @@ public class ControlCenterServiceHandler extends Handler {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
super.handleMessage(msg); super.handleMessage(msg);
// 解析线程传递的完整数据obj=提醒类型(+/-)arg1=当前电量arg2=充电状态(1=充电中,0=未充电) // 解析消息参数obj=提醒类型(+/-)arg1=当前电量arg2=充电状态(1=充电/0=未充电)
String remindType = (msg.obj != null) ? (String) msg.obj : ""; String remindType = (msg.obj != null) ? (String) msg.obj : "";
int currentBattery = msg.arg1; int currentBattery = msg.arg1;
boolean isCharging = msg.arg2 == 1; 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(); ControlCenterService service = mwrControlCenterService.get();
if (service == null) { if (service == null) {
LogUtils.e(TAG, "服务实例已回收,消息处理失败"); LogUtils.e(TAG, "服务实例已回收,终止消息处理");
return; return;
} }
// 按消息类型分发处理,避免逻辑冗余 // 按消息类型分发处理
switch (msg.what) { switch (msg.what) {
case MSG_REMIND_TEXT: case MSG_REMIND_TEXT:
handleRemindMessage(service, remindType, currentBattery, isCharging); handleRemindMessage(service, remindType, currentBattery, isCharging);
break; break;
default: default:
LogUtils.w(TAG, "未知消息类型what" + msg.what); LogUtils.w(TAG, "未知消息类型 | what=" + msg.what);
break; break;
} }
} }
// ================================== 业务辅助方法(重构通知内容,格式:(+/-)(当前电量)(充电状态)================================= // ================================== 业务辅助方法(构建通知并发送,全链路参数校验=================================
/** /**
* 处理电量提醒消息,构建带电量+充电状态的通知模型 * 处理电量提醒消息,构建带电量+充电状态的通知并发送
* @param service 服务实例(非空,已前置校验 * @param service 控制中心服务实例(已校验非空
* @param remindType 提醒类型(+充电提醒,-:耗电提醒 * @param remindType 提醒类型(+充电/-耗电
* @param currentBattery 当前电量0-100 * @param currentBattery 当前电量0-100
* @param isCharging 充电状态true=充电中false=未充电) * @param isCharging 充电状态
*/ */
private void handleRemindMessage(ControlCenterService service, String remindType, int currentBattery, boolean 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) { if (service.getNotificationManager() == null) {
LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒"); LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒");
return; return;
} }
if (!"+".equals(remindType) && !"-".equals(remindType)) { if (!REMIND_TYPE_CHARGE.equals(remindType) && !REMIND_TYPE_USAGE.equals(remindType)) {
LogUtils.w(TAG, "无效提醒类型,跳过发送:" + remindType); LogUtils.w(TAG, "无效提醒类型 | type=" + remindType);
return; return;
} }
if (currentBattery < 0 || currentBattery > 100) { if (currentBattery < BATTERY_LEVEL_MIN || currentBattery > BATTERY_LEVEL_MAX) {
LogUtils.w(TAG, "无效当前电量,跳过发送:" + currentBattery); LogUtils.w(TAG, "无效电量值 | battery=" + currentBattery + "需在0-100范围内");
return; return;
} }
// 2. 构建通知模型,按格式拼接内容(核心优化) // 2. 构建通知模型,使用String.format统一格式
NotificationMessage remindMsg = new NotificationMessage(); NotificationMessage remindMsg = new NotificationMessage();
String chargeStateDesc = isCharging ? "充电中" : "未充电"; // 充电状态文字描述 String chargeStateDesc = isCharging ? "充电中" : "未充电";
if ("+".equals(remindType)) { if (REMIND_TYPE_CHARGE.equals(remindType)) {
// 充电提醒:格式 (+)(当前电量)(充电状态)
remindMsg.setTitle("充电提醒"); remindMsg.setTitle("充电提醒");
remindMsg.setContent("(+) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已达标建议及时断电,保护电池寿命~"); remindMsg.setContent(String.format("(+) 当前电量%d%%%s已达标建议及时断电保护电池寿命", currentBattery, chargeStateDesc));
remindMsg.setRemindMSG("charge_remind"); remindMsg.setRemindMSG("charge_remind");
LogUtils.d(TAG, "构建充电提醒通知,内容:" + remindMsg.getContent()); } else {
} else if ("-".equals(remindType)) {
// 耗电提醒:格式 (-)(当前电量)(充电状态)
remindMsg.setTitle("耗电提醒"); remindMsg.setTitle("耗电提醒");
remindMsg.setContent("(-) 当前电量" + currentBattery + "%" + chargeStateDesc + ",已偏低建议及时充电,避免设备关机~"); remindMsg.setContent(String.format("(-) 当前电量%d%%%s已偏低建议及时充电避免设备关机", currentBattery, chargeStateDesc));
remindMsg.setRemindMSG("usage_remind"); 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); 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; import java.lang.ref.WeakReference;
/** /**
* 控制中心广播接收器 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* 功能:监听电池状态变化、通知更新、线程启动指令 * @Date 2025/12/19 20:23
* 适配Java7 | API30 | 小米手机 | 内存泄漏防护 * @Describe 控制中心广播接收器
* 功能:监听电池状态变化、前台通知更新、配置变更指令
* 适配Java7 | API30 | 内存泄漏防护 | 多线程状态同步
*/ */
public class ControlCenterServiceReceiver extends BroadcastReceiver { public class ControlCenterServiceReceiver extends BroadcastReceiver {
// ================================== 静态常量区(置顶归类,消除魔法值)================================= // ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = ControlCenterServiceReceiver.class.getSimpleName(); public static final String TAG = ControlCenterServiceReceiver.class.getSimpleName();
// 广播Action常量带包名前缀防冲突 // 广播Action常量带包名前缀防冲突
public static final String ACTION_UPDATE_SERVICENOTIFICATION = "cc.winboll.studio.powerbell.action.UPDATE_SERVICENOTIFICATION"; public static final String ACTION_UPDATE_FOREGROUND_NOTIFICATION = "cc.winboll.studio.powerbell.action.ACTION_UPDATE_SERVICE_FOREGROUND_NOTIFICATION";
public static final String ACTION_START_REMINDTHREAD = "cc.winboll.studio.powerbell.action.START_REMINDTHREAD"; 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"; 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 BROADCAST_PRIORITY = IntentFilter.SYSTEM_HIGH_PRIORITY - 10;
private static final int BATTERY_LEVEL_MIN = 0;
private static final int BATTERY_LEVEL_MAX = 100;
// ================================== 成员变量区弱引用防泄漏volatile保线程安全================================= // ================================== 成员变量区弱引用防泄漏volatile保线程安全=================================
private WeakReference<ControlCenterService> mwrControlCenterService; private WeakReference<ControlCenterService> mwrControlCenterService;
private static volatile int sLastBatteryLevel = -1; private static volatile int sLastBatteryLevel = -1; // 上次电量(多线程可见)
private static volatile boolean sIsCharging = false; private static volatile boolean sIsCharging = false; // 上次充电状态(多线程可见)
// ================================== 构造方法(初始化弱引用,避免内存泄漏)================================= // ================================== 构造方法(初始化弱引用,避免服务强引用泄漏)=================================
public ControlCenterServiceReceiver(ControlCenterService service) { 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); this.mwrControlCenterService = new WeakReference<>(service);
} }
// ================================== 广播核心接收逻辑入口方法分Action处理================================= // ================================== 广播核心接收逻辑入口方法分Action分发处理)=================================
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null")); LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null"));
@@ -63,14 +67,14 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
// 分Action处理业务逻辑 // 分Action处理业务逻辑
String action = intent.getAction(); String action = intent.getAction();
switch (action) { switch (action) {
case ACTION_UPDATE_SERVICENOTIFICATION:
handleUpdateServiceNotification(service);
break;
case Intent.ACTION_BATTERY_CHANGED: case Intent.ACTION_BATTERY_CHANGED:
handleBatteryStateChanged(context, service, intent); handleBatteryStateChanged(service, intent);
break; break;
case ACTION_START_REMINDTHREAD: case ACTION_UPDATE_FOREGROUND_NOTIFICATION:
LogUtils.d(TAG, "onReceive: ACTION_START_REMINDTHREAD 逻辑待实现"); handleUpdateForegroundNotification(service);
break;
case ACTION_APPCONFIG_CHANGED:
handleNotifyAppConfigUpdate(service);
break; break;
default: default:
LogUtils.w(TAG, "onReceive: 未知Action=" + action); LogUtils.w(TAG, "onReceive: 未知Action=" + action);
@@ -79,44 +83,20 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
LogUtils.d(TAG, "onReceive: 广播处理完成"); 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 service 控制中心服务实例
* @param intent 广播意图 * @param intent 电池状态广播意图
*/ */
private void handleBatteryStateChanged(Context context, ControlCenterService service, Intent intent) { private void handleBatteryStateChanged(ControlCenterService service, Intent intent) {
LogUtils.d(TAG, "handleBatteryStateChanged: 处理电池状态变化 | context=" + context + " | service=" + service); LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | service=" + service);
try { try {
// 1. 获取并校验当前电池状态 // 1. 解析并校验当前电池状态
boolean currentCharging = BatteryUtils.isCharging(context); boolean currentCharging = BatteryUtils.isCharging(intent);
int currentBatteryLevel = BatteryUtils.getCurrentBattery(context); int currentBatteryLevel = BatteryUtils.getCurrentBatteryLevel(intent);
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, 0), 100); currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
LogUtils.d(TAG, "handleBatteryStateChanged: 当前状态 | 充电=" + currentCharging + " | 电量=" + currentBatteryLevel); LogUtils.d(TAG, "handleBatteryStateChanged: 当前状态 | 充电=" + currentCharging + " | 电量=" + currentBatteryLevel + "%");
// 2. 状态无变化则跳过,减少无效运算 // 2. 状态无变化则跳过,减少无效运算
if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) { if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) {
@@ -124,8 +104,8 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
return; return;
} }
// 3. 加载最新配置(级兜底) // 3. 加载最新配置(级兜底:本地配置→服务内存配置→默认配置
AppConfigBean latestConfig = loadLatestConfig(context); AppConfigBean latestConfig = loadLatestConfig(service);
if (latestConfig == null) { if (latestConfig == null) {
latestConfig = service.getCurrentConfigBean(); latestConfig = service.getCurrentConfigBean();
if (latestConfig == null) { if (latestConfig == null) {
@@ -134,29 +114,80 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
} }
} }
// 4. 同步电池状态到配置,更新服务与线程 // 4. 同步电池状态到配置,通知服务更新线程
latestConfig.setCurrentBatteryValue(currentBatteryLevel); latestConfig.setCurrentBatteryValue(currentBatteryLevel);
latestConfig.setIsCharging(currentCharging); latestConfig.setIsCharging(currentCharging);
service.notifyAppConfigUpdate(latestConfig); service.notifyAppConfigUpdate(latestConfig);
// 5. 缓存最新状态,保多线程可见 // 5. 更新静态缓存状态,保多线程可见
sIsCharging = currentCharging; sIsCharging = currentCharging;
sLastBatteryLevel = currentBatteryLevel; sLastBatteryLevel = currentBatteryLevel;
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功"); LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态处理成功");
} catch (Exception e) { } 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 上下文 * @param context 上下文
* @return 最新配置实例失败返回null * @return 最新配置实例失败返回null
*/ */
private AppConfigBean loadLatestConfig(Context context) { private AppConfigBean loadLatestConfig(Context context) {
LogUtils.d(TAG, "loadLatestConfig: 加载最新配置 | context=" + context); LogUtils.d(TAG, "loadLatestConfig: 读取本地配置 | context=" + context);
try { try {
if (context == null) { if (context == null) {
LogUtils.e(TAG, "loadLatestConfig: 上下文为空"); LogUtils.e(TAG, "loadLatestConfig: 上下文为空");
@@ -170,10 +201,10 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
} }
configUtils.reloadAllConfig(); configUtils.reloadAllConfig();
LogUtils.d(TAG, "loadLatestConfig: 配置加载成功"); LogUtils.d(TAG, "loadLatestConfig: 本地配置加载成功");
return configUtils.mAppConfigBean; return configUtils.mAppConfigBean;
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "loadLatestConfig: 配置加载失败", e); LogUtils.e(TAG, "loadLatestConfig: 加载失败", e);
return null; return null;
} }
} }
@@ -184,7 +215,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
* @param context 上下文 * @param context 上下文
*/ */
public void registerAction(Context context) { public void registerAction(Context context) {
LogUtils.d(TAG, "registerAction: 注册广播 | context=" + context); LogUtils.d(TAG, "registerAction: 注册广播接收器 | context=" + context);
if (context == null) { if (context == null) {
LogUtils.e(TAG, "registerAction: 上下文为空,注册失败"); LogUtils.e(TAG, "registerAction: 上下文为空,注册失败");
return; return;
@@ -195,15 +226,15 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
unregisterAction(context); unregisterAction(context);
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_UPDATE_SERVICENOTIFICATION);
filter.addAction(ACTION_START_REMINDTHREAD);
filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_UPDATE_FOREGROUND_NOTIFICATION);
filter.addAction(ACTION_APPCONFIG_CHANGED);
filter.setPriority(BROADCAST_PRIORITY); filter.setPriority(BROADCAST_PRIORITY);
context.registerReceiver(this, filter); context.registerReceiver(this, filter);
LogUtils.d(TAG, "registerAction: 广播注册成功"); LogUtils.d(TAG, "registerAction: 广播注册成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "registerAction: 广播注册失败", e); LogUtils.e(TAG, "registerAction: 注册失败", e);
} }
} }
@@ -212,7 +243,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
* @param context 上下文 * @param context 上下文
*/ */
public void unregisterAction(Context context) { public void unregisterAction(Context context) {
LogUtils.d(TAG, "unregisterAction: 注销广播 | context=" + context); LogUtils.d(TAG, "unregisterAction: 注销广播接收器 | context=" + context);
if (context == null) { if (context == null) {
LogUtils.e(TAG, "unregisterAction: 上下文为空,注销失败"); LogUtils.e(TAG, "unregisterAction: 上下文为空,注销失败");
return; return;
@@ -224,7 +255,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销"); LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销");
} catch (Exception e) { } 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() { public void release() {
LogUtils.d(TAG, "release: 释放广播接收器资源"); LogUtils.d(TAG, "release: 释放广播接收器资源");
// 清空弱引用 // 清空弱引用帮助GC回收
if (mwrControlCenterService != null) { if (mwrControlCenterService != null) {
mwrControlCenterService.clear(); mwrControlCenterService.clear();
mwrControlCenterService = null; 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.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BatteryUtils; 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 class GlobalApplicationReceiver extends BroadcastReceiver {
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = "GlobalApplicationReceiver"; 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 App mGlobalApplication;
// 存储历史电池状态,用于判断变化(优化命名,明确语义)
private static volatile int sLastBatteryLevel = -1; // 历史电量0-100 private static volatile int sLastBatteryLevel = -1; // 历史电量0-100
private static volatile boolean sLastIsCharging = false; // 历史充电状态 private static volatile boolean sLastIsCharging = false; // 历史充电状态
// 当前Receiver实例优化命名避免歧义
// ================================== 成员变量区(按功能分层)=================================
private App mGlobalApplication;
private AppConfigUtils mAppConfigUtils;
private GlobalApplicationReceiver mCurrentReceiver; private GlobalApplicationReceiver mCurrentReceiver;
// 构造方法(强化参数校验,避免空指针) // ================================== 构造方法(强化参数校验,初始化核心依赖)=================================
public GlobalApplicationReceiver(App globalApplication) { public GlobalApplicationReceiver(App globalApplication) {
LogUtils.d(TAG, "构造接收器 | App=" + globalApplication);
if (globalApplication == null) { if (globalApplication == null) {
LogUtils.e(TAG, "GlobalApplicationReceiver: App instance is null"); LogUtils.e(TAG, "构造失败App实例为空");
throw new IllegalArgumentException("App cannot be null"); throw new IllegalArgumentException("App cannot be null");
} }
this.mCurrentReceiver = this; this.mCurrentReceiver = this;
this.mGlobalApplication = globalApplication; this.mGlobalApplication = globalApplication;
this.mAppConfigUtils = App.getAppConfigUtils(mGlobalApplication); this.mAppConfigUtils = App.getAppConfigUtils(mGlobalApplication);
LogUtils.d(TAG, "构造完成AppConfigUtils=" + mAppConfigUtils);
} }
// ================================== 广播核心接收逻辑(入口方法,过滤电池状态广播)=================================
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
LogUtils.d(TAG, "onReceive: enter, action=" + intent.getAction()); LogUtils.d(TAG, "onReceive: 接收广播 | context=" + context + " | intent=" + intent + " | action=" + (intent != null ? intent.getAction() : "null"));
// 双重空指针防护context/intent/action 均校验)
// 基础参数校验
if (context == null || 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; return;
} }
@@ -46,99 +60,119 @@ public class GlobalApplicationReceiver extends BroadcastReceiver {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
handleBatteryStateChanged(context, intent); handleBatteryStateChanged(context, intent);
} }
LogUtils.d(TAG, "onReceive: exit");
LogUtils.d(TAG, "onReceive: 广播处理完成");
} }
// ================================== 业务逻辑方法(处理电池状态变化,同步配置+通知页面)=================================
/** /**
* 处理电池状态变化(核心逻辑:复用 BatteryUtils优化状态同步 * 处理电池状态变化广播
* @param context 上下文
* @param intent 电池状态广播意图
*/ */
private void handleBatteryStateChanged(Context context, Intent intent) { private void handleBatteryStateChanged(Context context, Intent intent) {
// 1. 用 BatteryUtils 解析当前电池状态(复用工具类,避免重复代码) LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态 | intent=" + intent);
boolean currentIsCharging = BatteryUtils.isCharging(context); // 调用工具类判断充电状态 // 1. 解析当前电池状态(复用工具类,二次校验电量范围)
int currentBatteryLevel = BatteryUtils.getCurrentBattery(context); // 调用工具类获取电量0-100 boolean currentIsCharging = BatteryUtils.isCharging(intent);
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, 0), 100); // 二次校验,确保范围有效 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) { if (currentIsCharging == sLastIsCharging && currentBatteryLevel == sLastBatteryLevel) {
LogUtils.d(TAG, "handleBatteryStateChanged: no state change, skip"); LogUtils.d(TAG, "handleBatteryStateChanged: 状态无变化,跳过处理");
return; return;
} }
// 3. 同步最新状态到配置工具类(确保配置实时更新) // 3. 同步最新状态到配置工具类
if (mAppConfigUtils != null) { if (mAppConfigUtils != null) {
if (currentIsCharging != sLastIsCharging) { if (currentIsCharging != sLastIsCharging) {
mAppConfigUtils.setCharging(currentIsCharging); // 同步充电状态 mAppConfigUtils.setCharging(currentIsCharging);
LogUtils.d(TAG, "handleBatteryStateChanged: 同步充电状态 | " + currentIsCharging);
} }
if (currentBatteryLevel != sLastBatteryLevel) { if (currentBatteryLevel != sLastBatteryLevel) {
mAppConfigUtils.setCurrentBatteryValue(currentBatteryLevel); // 同步当前电量 mAppConfigUtils.setCurrentBatteryValue(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 同步电量 | " + currentBatteryLevel + "%");
} }
} else { } else {
LogUtils.e(TAG, "handleBatteryStateChanged: AppConfigUtils is null, sync failed"); LogUtils.e(TAG, "handleBatteryStateChanged: AppConfigUtils为空,同步失败");
} }
// 4. 电池状态变化后的业务逻辑(保留原有逻辑,强化空指针防护) // 4. 执行状态变化后的业务逻辑
// 取消旧提醒(若后续需要启用,可调用 NotificationHelper.cancelRemindNotification(context)
// 记录电量变化时间 // 记录电量变化时间
if (App.getAppCacheUtils(context) != null) { if (App.getAppCacheUtils(context) != null) {
App.getAppCacheUtils(context).addChangingTime(currentBatteryLevel); App.getAppCacheUtils(context).addChangingTime(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 记录电量变化时间");
} }
// 发送电量更新消息到MainActivity // 通知MainActivity更新电量
MainActivity.sendCurrentBatteryValueMessage(currentBatteryLevel); MainActivity.sendCurrentBatteryValueMessage(currentBatteryLevel);
LogUtils.d(TAG, "handleBatteryStateChanged: 发送电量更新消息到MainActivity");
// 5. 更新历史状态缓存volatile 保证多线程可见性) // 5. 更新历史状态缓存
sLastIsCharging = currentIsCharging; sLastIsCharging = currentIsCharging;
sLastBatteryLevel = currentBatteryLevel; sLastBatteryLevel = currentBatteryLevel;
LogUtils.d(TAG, "handleBatteryStateChanged: sync success, update last state"); LogUtils.d(TAG, "handleBatteryStateChanged: 更新历史状态完成");
} }
// 注册广播(优化容错,避免重复注册) // ================================== 广播注册/注销(强化容错,避免重复操作)=================================
/**
* 注册广播接收器
*/
public void registerAction() { public void registerAction() {
LogUtils.d(TAG, "registerAction: 注册广播");
if (mGlobalApplication == null || mCurrentReceiver == null) { if (mGlobalApplication == null || mCurrentReceiver == null) {
LogUtils.e(TAG, "registerAction: App/receiver is null, register failed"); LogUtils.e(TAG, "注册失败:App或Receiver实例为空");
return; return;
} }
try { try {
// 先注销再注册,避免重复注册导致异常 // 先注销再注册,避免重复注册异常
unregisterAction(); unregisterAction();
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_BATTERY_CHANGED);
mGlobalApplication.registerReceiver(mCurrentReceiver, filter); mGlobalApplication.registerReceiver(mCurrentReceiver, filter);
LogUtils.d(TAG, "registerAction: broadcast receiver registered success"); LogUtils.d(TAG, "registerAction: 广播注册成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "registerAction: register failed", e); LogUtils.e(TAG, "registerAction: 注册失败", e);
} }
} }
// 新增:注销广播(避免内存泄漏,供外部调用) /**
* 注销广播接收器
*/
public void unregisterAction() { public void unregisterAction() {
LogUtils.d(TAG, "unregisterAction: 注销广播");
if (mGlobalApplication == null || mCurrentReceiver == null) { if (mGlobalApplication == null || mCurrentReceiver == null) {
LogUtils.e(TAG, "unregisterAction: App/receiver is null, unregister failed"); LogUtils.e(TAG, "注销失败:App或Receiver实例为空");
return; return;
} }
try { try {
mGlobalApplication.unregisterReceiver(mCurrentReceiver); mGlobalApplication.unregisterReceiver(mCurrentReceiver);
LogUtils.d(TAG, "unregisterAction: broadcast receiver unregistered success"); LogUtils.d(TAG, "unregisterAction: 广播注销成功");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
LogUtils.w(TAG, "unregisterAction: receiver not registered, skip"); LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "unregisterAction: unregister failed", e); LogUtils.e(TAG, "unregisterAction: 注销失败", e);
} }
} }
// 新增主动释放资源供App销毁时调用彻底防泄漏 // ================================== 资源释放方法(主动释放,彻底避免内存泄漏)=================================
/**
* 释放接收器资源供App销毁时调用
*/
public void release() { public void release() {
LogUtils.d(TAG, "release: receiver release resources"); LogUtils.d(TAG, "release: 释放接收器资源");
// 注销广播
unregisterAction(); unregisterAction();
// 置空引用帮助GC回收
mGlobalApplication = null; mGlobalApplication = null;
mAppConfigUtils = null; mAppConfigUtils = null;
mCurrentReceiver = null; mCurrentReceiver = null;
// 重置静态缓存 // 重置静态状态缓存
sLastBatteryLevel = -1; sLastBatteryLevel = -1;
sLastIsCharging = false; sLastIsCharging = false;
LogUtils.d(TAG, "release: 资源释放完成");
} }
} }

View File

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

View File

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