服务线程调试中,目标就是线程放入服务类使用handler与服务通信。

This commit is contained in:
2025-12-18 21:15:24 +08:00
parent 7d796b5c3f
commit b0dee5e98e
5 changed files with 730 additions and 917 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Thu Dec 18 09:51:07 GMT 2025
#Thu Dec 18 12:48:12 GMT 2025
stageCount=10
libraryProject=
baseVersion=15.14
publishVersion=15.14.9
buildCount=35
buildCount=42
baseBetaVersion=15.14.10

View File

@@ -45,43 +45,42 @@ import cc.winboll.studio.powerbell.views.MainContentView;
* @Date 2025/12/17 13:14
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
* 适配Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
* 核心规则UI开关仅管理本地配置服务启停仅在应用启动时根据配置执行
* 核心规则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 int REQUEST_READ_MEDIA_IMAGES = 1001;
// 延迟时间
private static final int DELAY_LOAD_NON_CRITICAL = 500; // 非核心视图延迟加载ms
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_RESTART_REMIND_THREAD = 3; // 重启RemindThread线程
private static final int MSG_UPDATE_SERVICE_SWITCH = 4; // 更新服务开关UI
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 MainActivity sMainActivity; // 全局Activity实例销毁时必须置空
private static Handler sGlobalHandler; // 全局Handler统一消息分发
private static MainActivity sMainActivity;
private static Handler sGlobalHandler;
// ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减========================
// 工具类实例(单例,避免重复初始化)
// ======================== 工具类实例(单例,避免重复初始化========================
private PermissionUtils mPermissionUtils;
private AppConfigUtils mAppConfigUtils;
private BackgroundSourceUtils mBgSourceUtils;
// 应用核心实例
// ======================== 应用核心实例 =========================
private App mApplication;
private MainContentView mMainContentView; // 核心视图封装类
// 基础视图组件
private MainContentView mMainContentView;
private ControlCenterServiceBean mServiceControlBean;
// ======================== 基础视图组件 =========================
private Toolbar mToolbar;
private ViewStub mAdsViewStub;
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
// 资源与菜单
private ADsBannerView mADsBannerView;
private Drawable mFrameDrawable;
private Menu mMenu;
private Drawable mFrameDrawable; // 框架背景资源
// 服务控制核心Bean
private ControlCenterServiceBean mServiceControlBean;
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
@Override
@@ -96,83 +95,79 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 进入");
LogUtils.d(TAG, "onCreate: start");
super.onCreate(savedInstanceState);
// 1. 初始化全局Handler(优先初始化,避免消息丢失
// 优先初始化全局Handler避免消息丢失
initGlobalHandler();
// 2. 加载布局+初始化核心流程
// 布局与核心流程初始化
setContentView(R.layout.activity_main);
initPermissionUtils();
initMainContentView();
initCriticalView();
initCoreUtilsAsync();
loadNonCriticalViewDelayed();
LogUtils.d(TAG, "onCreate: 退出");
LogUtils.d(TAG, "onCreate: end");
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onPostCreate: 进入");
LogUtils.d(TAG, "onPostCreate: start");
super.onPostCreate(savedInstanceState);
mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 退出");
LogUtils.d(TAG, "onPostCreate: end");
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume: 进入");
LogUtils.d(TAG, "onResume: start");
super.onResume();
// 恢复背景+同步服务开关UI(仅本地配置)
// 恢复背景服务开关UI
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "onResume: 发送背景加载+服务开关更新消息");
LogUtils.d(TAG, "onResume: send MSG_LOAD_BACKGROUND & MSG_UPDATE_SERVICE_SWITCH");
}
// 恢复广告
if (mADsBannerView != null) {
mADsBannerView.resumeADs(this);
}
// // 设置RemindThread前台状态
// setRemindThreadForeground(true);
LogUtils.d(TAG, "onResume: 退出");
LogUtils.d(TAG, "onResume: end");
}
@Override
protected void onPause() {
LogUtils.d(TAG, "onPause: 进入");
LogUtils.d(TAG, "onPause: start");
super.onPause();
// // 设置RemindThread后台状态
// setRemindThreadForeground(false);
LogUtils.d(TAG, "onPause: 退出");
LogUtils.d(TAG, "onPause: end");
}
@Override
protected void onDestroy() {
LogUtils.d(TAG, "onDestroy: 进入");
LogUtils.d(TAG, "onDestroy: start");
super.onDestroy();
// 1. 释放广告资源
// 释放广告资源
if (mADsBannerView != null) {
mADsBannerView.releaseAdResources();
mADsBannerView = null;
}
// 2. 释放核心视图资源
// 释放核心视图
if (mMainContentView != null) {
mMainContentView.releaseResources();
mMainContentView = null;
}
// 3. 销毁线程+清理Handler
RemindThread.destroyInstance();
// 销毁线程Handler
RemindThread.stopRemindThread();
if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null;
}
// 4. 释放Drawable+置空全局实例
// 释放Drawable,防止内存泄漏
if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null);
mFrameDrawable = null;
}
// 置空所有引用
sMainActivity = null;
// 5. 置空所有辅助实例
mPermissionUtils = null;
mAppConfigUtils = null;
mBgSourceUtils = null;
@@ -181,27 +176,24 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mApplication = null;
mToolbar = null;
mAdsViewStub = null;
LogUtils.d(TAG, "onDestroy: 退出");
LogUtils.d(TAG, "onDestroy: end");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
LogUtils.d(TAG, "onActivityResult: 进入,requestCode=" + requestCode + "resultCode=" + resultCode);
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode);
super.onActivityResult(requestCode, resultCode, data);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 背景设置完成后重新加载背景
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
}
// 背景设置完成后重新加载
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: 进入");
LogUtils.d(TAG, "onCreateOptionsMenu: start");
mMenu = menu;
AESThemeUtil.inflateMenu(this, menu);
if (App.isDebugging()) {
@@ -209,13 +201,13 @@ 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: 退出");
LogUtils.d(TAG, "onCreateOptionsMenu: end");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected: 进入,itemId=" + item.getItemId());
LogUtils.d(TAG, "onOptionsItemSelected: itemId=" + item.getItemId());
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate();
return true;
@@ -245,7 +237,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
default:
return super.onOptionsItemSelected(item);
}
LogUtils.d(TAG, "onOptionsItemSelected: 退出");
return true;
}
@@ -260,7 +251,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void onBackPressed() {
moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用退到后台");
LogUtils.d(TAG, "onBackPressed: app move to background");
}
@Override
@@ -270,26 +261,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 核心初始化方法 ========================
private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: 进入");
LogUtils.d(TAG, "initPermissionUtils: start");
mPermissionUtils = PermissionUtils.getInstance();
LogUtils.d(TAG, "initPermissionUtils: 退出");
LogUtils.d(TAG, "initPermissionUtils: end");
}
/**
* 初始化全局Handler核心优化弱引用+生命周期校验,杜绝内存泄漏)
*/
private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: 进入");
LogUtils.d(TAG, "initGlobalHandler: start");
if (sGlobalHandler == null) {
sGlobalHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 严格校验Activity状态避免销毁后操作UI
// 校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁,跳过消息处理");
LogUtils.w(TAG, "handleMessage: Activity destroyed, skip msg what=" + msg.what);
return;
}
LogUtils.d(TAG, "handleMessage: 接收消息,what=" + msg.what);
LogUtils.d(TAG, "handleMessage: receive msg what=" + msg.what);
switch (msg.what) {
case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData();
@@ -303,32 +291,30 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sMainActivity.reloadBackground();
sMainActivity.setMainLayoutBackgroundColor();
break;
case MSG_RESTART_REMIND_THREAD:
case MSG_START_REMIND_THREAD:
AppConfigBean configBean = (AppConfigBean) msg.obj;
sMainActivity.restartRemindThread(configBean);
LogUtils.d(TAG, "MSG_START_REMIND_THREAD not yet.");
break;
case MSG_UPDATE_SERVICE_SWITCH:
sMainActivity.updateServiceSwitchUI();
break;
}
super.handleMessage(msg);
}
};
LogUtils.d(TAG, "initGlobalHandler: 全局Handler初始化完成");
LogUtils.d(TAG, "initGlobalHandler: handler created");
}
LogUtils.d(TAG, "initGlobalHandler: 退出");
LogUtils.d(TAG, "initGlobalHandler: end");
}
private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: 进入");
LogUtils.d(TAG, "initMainContentView: start");
View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this);
LogUtils.d(TAG, "initMainContentView: 核心视图封装类初始化完成");
LogUtils.d(TAG, "initMainContentView: 退出");
LogUtils.d(TAG, "initMainContentView: MainContentView created");
}
private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: 进入");
LogUtils.d(TAG, "initCriticalView: start");
sMainActivity = this;
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
@@ -336,81 +322,75 @@ 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: 退出");
LogUtils.d(TAG, "initCriticalView: end");
}
/**
* 异步初始化核心工具类(保留服务启停逻辑:应用启动时根据配置执行)
*/
private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: 进入");
LogUtils.d(TAG, "initCoreUtilsAsync: start");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
LogUtils.d(TAG, "initCoreUtilsAsync: async thread start");
mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
// 初始化服务控制Bean优先读取本地配置无则创建默认
// 初始化服务控制配置
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 创建默认服务控制配置(禁用)");
LogUtils.d(TAG, "initCoreUtilsAsync: create default service config (disabled)");
}
// 应用启动时:根据本地配置执行服务启停(仅执行一次)
if (mServiceControlBean.isEnableService()) {
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置启动服务");
}
});
}
} else {
if (ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置停止服务");
}
});
}
// 根据配置启停服务
final boolean isServiceEnable = mServiceControlBean.isEnableService();
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
if (isServiceEnable && !isServiceAlive) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: start service by config");
}
});
} else if (!isServiceEnable && isServiceAlive) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: stop service by config");
}
});
}
// 切换主线程更新UI
// 主线程更新UI
runOnUiThread(new Runnable() {
@Override
public void run() {
if (isFinishing() || isDestroyed()) {
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
LogUtils.w(TAG, "initCoreUtilsAsync: Activity destroyed, skip UI update");
return;
}
// 适配API30+主题加载Drawable
// 加载框架背景
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
} else {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame);
}
// 执行核心业务
updateViewData();
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
}
});
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
LogUtils.d(TAG, "initCoreUtilsAsync: async thread end");
}
}).start();
LogUtils.d(TAG, "initCoreUtilsAsync: 退出");
LogUtils.d(TAG, "initCoreUtilsAsync: end");
}
private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入");
LogUtils.d(TAG, "loadNonCriticalViewDelayed: start");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
@@ -420,38 +400,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
loadAdsView();
}
}, DELAY_LOAD_NON_CRITICAL);
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出");
LogUtils.d(TAG, "loadNonCriticalViewDelayed: end");
}
// ======================== 视图操作方法 ========================
private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 进入");
LogUtils.d(TAG, "loadAdsView: start");
if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空");
LogUtils.e(TAG, "loadAdsView: AdsViewStub is null");
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: 进入");
LogUtils.d(TAG, "updateViewData: start");
if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空");
LogUtils.e(TAG, "updateViewData: MainContentView or FrameDrawable is null");
return;
}
mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
LogUtils.d(TAG, "updateViewData: 退出");
LogUtils.d(TAG, "updateViewData: view data updated");
}
private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: 进入");
LogUtils.d(TAG, "reloadBackground: start");
if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空");
LogUtils.e(TAG, "reloadBackground: MainContentView or BackgroundSourceUtils is null");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
@@ -460,133 +440,114 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
}
LogUtils.d(TAG, "reloadBackground: 退出");
LogUtils.d(TAG, "reloadBackground: end");
}
private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入");
LogUtils.d(TAG, "setMainLayoutBackgroundColor: start");
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效");
LogUtils.e(TAG, "setMainLayoutBackgroundColor: invalid context");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
}
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出");
LogUtils.d(TAG, "setMainLayoutBackgroundColor: end");
}
/**
* 更新服务开关UI仅同步本地配置不校验服务状态
*/
private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI: 进入");
LogUtils.d(TAG, "updateServiceSwitchUI: start");
if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空");
LogUtils.e(TAG, "updateServiceSwitchUI: MainContentView or ServiceControlBean is null");
return;
}
// 仅读取本地配置状态,不涉及服务状态校验
boolean configEnabled = mServiceControlBean.isEnableService();
LogUtils.d(TAG, "updateServiceSwitchUI: 本地配置状态=" + configEnabled);
// 仅更新UI开关状态
LogUtils.d(TAG, "updateServiceSwitchUI: config enabled=" + configEnabled);
mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: 退出");
LogUtils.d(TAG, "updateServiceSwitchUI: end");
}
// ======================== 服务与线程管理方法 ========================
/**
* 重启提醒线程仅由配置变更触发不与UI开关联动
*/
private void restartRemindThread(AppConfigBean configBean) {
LogUtils.d(TAG, "restartRemindThread: 进入");
if (configBean == null || mServiceControlBean == null) {
LogUtils.e(TAG, "restartRemindThread: 配置/服务控制Bean为空");
return;
}
if (!mServiceControlBean.isEnableService()) {
LogUtils.w(TAG, "restartRemindThread: 服务已禁用,跳过线程重启");
return;
}
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext());
}
RemindThread.destroyInstance();
ControlCenterService.updateStatus(getApplicationContext(), configBean);
LogUtils.d(TAG, "restartRemindThread: 退出");
}
/**
* 设置线程前后台状态(依赖服务运行状态)
*/
// private void setRemindThreadForeground(boolean isForeground) {
// LogUtils.d(TAG, "setRemindThreadForeground: 进入,前台状态=" + isForeground);
// if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
// LogUtils.w(TAG, "setRemindThreadForeground: 服务未运行,跳过状态设置");
// 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;
// }
// try {
// RemindThread.getInstance(getApplicationContext(), null).setAppForeground(isForeground);
// } catch (IllegalArgumentException e) {
// LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化", e);
// if (!mServiceControlBean.isEnableService()) {
// LogUtils.w(TAG, "restartRemindThread: service is disabled, skip");
// return;
// }
// LogUtils.d(TAG, "setRemindThreadForeground: 退出");
// if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
// ControlCenterService.startControlCenterService(getApplicationContext());
// }
// RemindThread.destroyInstance();
// ControlCenterService.updateStatus(getApplicationContext(), configBean);
// LogUtils.d(TAG, "restartRemindThread: end");
// }
/**
* 切换服务启用状态仅持久化本地配置点击UI开关时不联动服务启停
*/
private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable);
LogUtils.d(TAG, "toggleServiceEnableState: target state=" + isEnable);
if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空");
LogUtils.e(TAG, "toggleServiceEnableState: ServiceControlBean is null");
return;
}
// 仅更新本地配置并持久化
mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 本地服务控制配置已持久化,状态=" + isEnable);
// 仅更新UI无服务启停操作
// ========== 核心新增逻辑UI开关联动服务启停 + 线程销毁 ==========
if (isEnable) {
// 开启:启动服务
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: start service success");
}
} else {
// 关闭:停止服务 + 销毁线程
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: stop service + destroy thread success");
}
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "toggleServiceEnableState: 退出");
LogUtils.d(TAG, "toggleServiceEnableState: config saved + service state synced");
}
// ======================== 页面跳转方法 ========================
private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: 进入");
LogUtils.d(TAG, "startAboutActivity: start");
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: 退出");
LogUtils.d(TAG, "startAboutActivity: end");
}
// ======================== 消息发送方法 ========================
private void sendRestartRemindThreadMessage() {
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入");
LogUtils.d(TAG, "sendRestartRemindThreadMessage: start");
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
LogUtils.e(TAG, "sendRestartRemindThreadMessage: 环境无效");
LogUtils.e(TAG, "sendRestartRemindThreadMessage: invalid context");
return;
}
Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD);
Message msg = sGlobalHandler.obtainMessage(MSG_START_REMIND_THREAD);
msg.obj = mAppConfigUtils.mAppConfigBean;
sGlobalHandler.sendMessage(msg);
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出");
LogUtils.d(TAG, "sendRestartRemindThreadMessage: msg sent");
}
// ======================== 静态工具方法 ========================
public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: 发送配置更新消息");
LogUtils.d(TAG, "reloadAppConfig: send MSG_RELOAD_APPCONFIG");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
}
}
public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value);
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: battery=" + value);
if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value;
@@ -596,9 +557,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 辅助工具方法 ========================
private String getRealPathFromUri(Uri contentUri) {
LogUtils.d(TAG, "getRealPathFromUri: 进入");
LogUtils.d(TAG, "getRealPathFromUri: uri=" + contentUri);
if (contentUri == null) {
LogUtils.e(TAG, "getRealPathFromUri: URI为空");
LogUtils.e(TAG, "getRealPathFromUri: Uri is null");
return null;
}
String realPath = null;
@@ -616,12 +577,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
cursor.close();
}
}
LogUtils.d(TAG, "getRealPathFromUri: 退出,路径=" + realPath);
LogUtils.d(TAG, "getRealPathFromUri: path=" + realPath);
return realPath;
}
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 进入");
LogUtils.d(TAG, "genDefaultAppInfo: start");
String branchName = "powerbell";
APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name));
@@ -634,39 +595,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: 退出");
LogUtils.d(TAG, "genDefaultAppInfo: end");
return appInfo;
}
// ======================== MainContentView 事件回调 ========================
@Override
public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 状态=" + isChecked);
LogUtils.d(TAG, "onChargeReminderSwitchChanged: isChecked=" + isChecked);
sendRestartRemindThreadMessage();
}
@Override
public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 状态=" + isChecked);
LogUtils.d(TAG, "onUsageReminderSwitchChanged: isChecked=" + isChecked);
sendRestartRemindThreadMessage();
}
@Override
public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
// 仅更新本地配置,不触发服务启停
LogUtils.d(TAG, "onServiceSwitchChanged: isChecked=" + isChecked);
toggleServiceEnableState(isChecked);
}
@Override
public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: 进度=" + progress);
LogUtils.d(TAG, "onChargeReminderProgressChanged: progress=" + progress);
sendRestartRemindThreadMessage();
}
@Override
public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: 进度=" + progress);
LogUtils.d(TAG, "onUsageReminderProgressChanged: progress=" + progress);
sendRestartRemindThreadMessage();
}
}

View File

@@ -216,19 +216,15 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
// 先同步完整配置核心setAppConfigBean已包含状态同步无需重复设置
remindThread.setAppConfigBean(config);
// 额外同步实时状态(兜底,确保最新)
remindThread.setIsCharging(isCharging);
remindThread.setQuantityOfElectricity(batteryLevel);
// 确保线程开启提醒功能
remindThread.setIsReminding(true);
// 线程未运行时唤醒,已运行时无需操作(避免重复唤醒导致逻辑紊乱)
if (!remindThread.isRunning()) {
synchronized (remindThread) {
remindThread.notify();
LogUtils.d(TAG, "updateRemindThreadConfig: remindThread is woken up");
}
}
//
//
// // 线程未运行时唤醒,已运行时无需操作(避免重复唤醒导致逻辑紊乱)
// if (!remindThread.isRunning()) {
// synchronized (remindThread) {
// remindThread.notify();
// LogUtils.d(TAG, "updateRemindThreadConfig: remindThread is woken up");
// }
// }
LogUtils.d(TAG, "updateRemindThreadConfig: success, thread config updated");
} catch (Exception e) {
LogUtils.e(TAG, "updateRemindThreadConfig: failed", e);

View File

@@ -1,7 +1,6 @@
package cc.winboll.studio.powerbell.services;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -10,11 +9,8 @@ import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.core.app.NotificationCompat;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.models.AppConfigBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
@@ -30,13 +26,15 @@ import java.util.List;
* @Describe 电池提醒核心服务修复前台服务超时异常优先在onCreate发送通知适配Java7+API30
*/
public class ControlCenterService extends Service {
// ================================== 静态常量(置顶统一管理,避免魔法值)=================================
// ================================== 静态常量(置顶统一管理,消除魔法值)=================================
public static final String TAG = "ControlCenterService";
// 服务指令常量(带包名前缀,防止冲突)
public static final String ACTION_RESTART_REMIND_THREAD = "cc.winboll.studio.powerbell.action.RESTART_REMIND_THREAD";
public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
// 超时常量
private static final long THREAD_STOP_TIMEOUT = 1000L;
// ================================== 成员变量(按功能分类,私有封装+并发锁保护=================================
// ================================== 成员变量(按功能分类,私有封装)=================================
// 服务控制核心
private ControlCenterServiceBean mServiceControlBean;
// 业务核心组件
@@ -45,184 +43,164 @@ public class ControlCenterService extends Service {
private NotificationManagerUtils mNotificationManager;
private AppConfigBean mCurrentConfigBean;
private NotificationMessage mForegroundNotifyMsg;
// 状态标记(复用 isServiceRunning 替代原 isCoreBusinessStarted
// 状态标记(volatile保证多线程可见性
private static volatile boolean isServiceRunning;
private static volatile boolean mIsDestroyed;
// ================================== 服务生命周期方法(核心流程入口)=================================
// ================================== 服务生命周期方法(核心流程入口,按执行顺序排列=================================
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate: 服务开始创建");
// 调用抽取的核心运行函数
LogUtils.d(TAG, "===== onCreate: 服务生命周期启动 =====");
LogUtils.d(TAG, "onCreate: 当前线程=" + Thread.currentThread().getName() + " | 进程ID=" + android.os.Process.myPid());
runCoreServiceLogic();
LogUtils.d(TAG, "onCreate: 服务创建完成,前台通知已发送,启用状态=" + mServiceControlBean.isEnableService());
LogUtils.d(TAG, "===== onCreate: 服务生命周期结束 | 前台通知状态=" + (isServiceRunning ? "✅已发送" : "❌未发送") + " | 启用状态=" + (mServiceControlBean != null ? mServiceControlBean.isEnableService() : false) + " =====");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand: 服务启动指令触发");
// 读取最新控制配置
LogUtils.d(TAG, "===== onStartCommand: 服务启动指令触发 =====");
LogUtils.d(TAG, "onStartCommand: intent=" + intent + " | flags=" + flags + " | startId=" + startId);
LogUtils.d(TAG, "onStartCommand: intent action=" + (intent != null ? intent.getAction() : "null"));
loadLatestServiceControlConfig();
// 调用抽取的核心运行函数
runCoreServiceLogic();
if (mServiceControlBean.isEnableService()) {
LogUtils.d(TAG, "onStartCommand: 服务已启用返回START_STICKY");
return START_STICKY;
} else {
return super.onStartCommand(intent, flags, startId);
}
int returnFlag;
if (mServiceControlBean != null && mServiceControlBean.isEnableService()) {
LogUtils.d(TAG, "onStartCommand: 服务已启用返回START_STICKY被杀死后自动重启");
returnFlag = START_STICKY;
} else {
LogUtils.d(TAG, "onStartCommand: 服务未启用,返回默认值");
returnFlag = super.onStartCommand(intent, flags, startId);
}
LogUtils.d(TAG, "===== onStartCommand: 服务启动指令处理完成 | 返回值=" + returnFlag + " =====");
return returnFlag;
}
@Override
public void onDestroy() {
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程启动 =====");
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 服务开始销毁");
// 顺序释放资源
stopForegroundService();
stopRemindThreadSafely();
destroyHandler();
releaseNotificationResource();
clearAllReferences();
// 重置核心业务标记
mCurrentConfigBean = null;
mForegroundNotifyMsg = null;
// 重置核心业务标记
mServiceHandler = null;
isServiceRunning = false;
mIsDestroyed = true;
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
// 重置核心状态标记
mCurrentConfigBean = null;
mForegroundNotifyMsg = null;
mServiceHandler = null;
isServiceRunning = false;
mIsDestroyed = true;
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程完成 =====");
}
@Override
public IBinder onBind(Intent intent) {
LogUtils.d(TAG, "onBind: 服务绑定请求 | intent=" + intent);
return null;
}
// ================================== 核心抽取函数】运行服务核心逻辑 =================================
// ================================== 核心业务逻辑(抽取独立方法,统一管理)=================================
/**
* 抽取的服务核心运行逻辑统一在onCreate和onStartCommand调用
* 复用 isServiceRunning 做重复运行判断,避免重复初始化业务
*/
private void runCoreServiceLogic() {
loadLatestServiceControlConfig();
// 核心校验:服务已启用 + 服务处于运行状态 + 未被销毁 + 业务未初始化通过mServiceHandler判空
if (mServiceControlBean.isEnableService()) {
if (!isServiceRunning) {
isServiceRunning = true;
mIsDestroyed = false;
LogUtils.d(TAG, "runCoreServiceLogic: 开始执行服务核心业务");
// 初始化通知 + 默认配置 + Handler + 线程
// 优先发送前台通知避免5秒超时异常
initForegroundNotificationImmediately();
// 加载本地服务控制配置
//initNotificationManager();
loadDefaultConfig();
initServiceBusinessLogic();
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务执行完成");
} else {
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务已在运行,无需重复执行");
}
} else {
LogUtils.d(TAG, "runCoreServiceLogic: 服务未启用,不执行核心业务");
}
LogUtils.d(TAG, "runCoreServiceLogic: 开始执行核心业务逻辑");
loadLatestServiceControlConfig();
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
LogUtils.d(TAG, "runCoreServiceLogic: 服务启用状态=" + serviceEnabled + " | 当前运行状态=" + isServiceRunning + " | 已销毁状态=" + mIsDestroyed);
// 核心校验:服务已启用 + 服务未运行 + 未被销毁
if (serviceEnabled) {
if (!isServiceRunning && !mIsDestroyed) {
isServiceRunning = true;
mIsDestroyed = false;
LogUtils.d(TAG, "runCoreServiceLogic: 满足执行条件,开始初始化前台通知和业务组件");
// 优先发送前台通知避免5秒超时异常
if (initForegroundNotificationImmediately()) {
loadDefaultConfig();
initServiceBusinessLogic();
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务组件初始化完成");
} else {
LogUtils.e(TAG, "runCoreServiceLogic: 前台通知初始化失败,终止核心业务执行");
stopForegroundService();
isServiceRunning = false;
}
} else {
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务已运行或服务已销毁,无需重复执行");
}
} else {
LogUtils.d(TAG, "runCoreServiceLogic: 服务未启用,跳过核心业务执行");
}
}
// ================================== 前台通知核心方法(优先执行,防止超时)=================================
// ================================== 前台通知管理(优先执行,防止超时异常=================================
/**
* 立即初始化前台通知,内置兜底方案
* @return true:通知初始化成功 false:通知初始化失败
*/
private void initForegroundNotificationImmediately() {
LogUtils.d(TAG, "initForegroundNotificationImmediately: 初始化前台通知");
private boolean initForegroundNotificationImmediately() {
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程启动");
try {
if (mNotificationManager == null) {
mNotificationManager = new NotificationManagerUtils(this);
LogUtils.d(TAG, "initForegroundNotificationImmediately: 通知工具类初始化完成");
}
if (mForegroundNotifyMsg == null) {
mForegroundNotifyMsg = new NotificationMessage();
mForegroundNotifyMsg.setTitle("电池监测服务");
mForegroundNotifyMsg.setContent("后台运行中");
mForegroundNotifyMsg.setRemindMSG("service_running");
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知消息构建完成 | 标题=" + mForegroundNotifyMsg.getTitle() + " | 内容=" + mForegroundNotifyMsg.getContent());
}
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
ToastUtils.show("startForegroundServiceNotify 已调用");
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
ToastUtils.show("startForegroundServiceNotify 已调用");
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功 | 通知ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程成功结束");
return true;
} catch (Exception e) {
LogUtils.e(TAG, "initForegroundNotificationImmediately: 工具类发送失败,执行兜底方案", e);
fallbackStartForeground();
LogUtils.e(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程异常", e);
return false;
}
}
/**
* 前台通知兜底方案直接构建Notification
* 停止前台服务并取消通知
*/
private void fallbackStartForeground() {
private void stopForegroundService() {
LogUtils.d(TAG, "stopForegroundService: 停止前台服务流程启动");
try {
Notification notification = new NotificationCompat.Builder(this, NotificationManagerUtils.CHANNEL_ID_FOREGROUND)
.setContentTitle("电池监测服务")
.setContentText("后台运行中")
.setSmallIcon(R.drawable.ic_launcher)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build();
startForeground(NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE, notification);
LogUtils.d(TAG, "fallbackStartForeground: 兜底前台通知发送成功");
stopForeground(true);
LogUtils.d(TAG, "stopForegroundService: 前台服务停止成功,通知已取消");
} catch (Exception e) {
LogUtils.e(TAG, "fallbackStartForeground: 兜底发送失败,服务会被系统杀死", e);
LogUtils.e(TAG, "stopForegroundService: 停止前台服务异常", e);
}
LogUtils.d(TAG, "stopForegroundService: 停止前台服务流程结束");
}
// ================================== 服务控制配置管理(本地持久化+内存同步)=================================
// ================================== 配置管理(本地持久化+内存同步)=================================
/**
* 读取本地最新服务控制配置
*/
private void loadLatestServiceControlConfig() {
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取本地配置");
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取本地服务控制配置");
ControlCenterServiceBean latestBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
if (latestBean != null) {
mServiceControlBean = latestBean;
LogUtils.d(TAG, "loadLatestServiceControlConfig: 配置更新完成,启用状态=" + mServiceControlBean.isEnableService());
} else {
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无配置,沿用当前状态");
}
if (latestBean != null) {
mServiceControlBean = latestBean;
LogUtils.d(TAG, "loadLatestServiceControlConfig: 本地配置读取成功 | 启用状态=" + mServiceControlBean.isEnableService());
} else {
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无配置文件,沿用当前内存配置 | 当前配置=" + mServiceControlBean);
}
}
/**
* 更新并持久化服务控制配置
*/
private void updateAndSaveServiceControlConfig(ControlCenterServiceBean newControlBean) {
ControlCenterServiceBean.saveBean(this, mServiceControlBean);
}
// ================================== 业务初始化与停止(按需加载,避免重复)=================================
/**
* 初始化通知管理工具类
*/
// private void initNotificationManager() {
// LogUtils.d(TAG, "initNotificationManager: 初始化通知工具");
// if (mNotificationManager == null) {
// mNotificationManager = new NotificationManagerUtils(this);
// }
// if (mForegroundNotifyMsg == null) {
// mForegroundNotifyMsg = new NotificationMessage();
// mForegroundNotifyMsg.setTitle("电池提醒服务运行中");
// mForegroundNotifyMsg.setContent("后台持续监测电池状态");
// mForegroundNotifyMsg.setRemindMSG("service_running");
// }
// }
/**
* 加载默认应用配置
*/
private void loadDefaultConfig() {
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置");
LogUtils.d(TAG, "loadDefaultConfig: 加载默认业务配置");
if (mCurrentConfigBean == null) {
mCurrentConfigBean = new AppConfigBean();
mCurrentConfigBean.setEnableChargeReminder(true);
@@ -230,242 +208,214 @@ public class ControlCenterService extends Service {
mCurrentConfigBean.setEnableUsageReminder(true);
mCurrentConfigBean.setUsageReminderValue(20);
mCurrentConfigBean.setBatteryDetectInterval(1000);
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成");
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成 | 充电阈值=" + 80 + " | 耗电阈值=" + 20 + " | 检测间隔=" + 1000 + "ms");
} else {
LogUtils.d(TAG, "loadDefaultConfig: 内存中已有业务配置,无需加载默认值 | 当前充电阈值=" + mCurrentConfigBean.getChargeReminderValue());
}
}
// ================================== 业务组件初始化与销毁=================================
/**
* 初始化业务核心逻辑Handler+线程)
*/
private void initServiceBusinessLogic() {
LogUtils.d(TAG, "initServiceBusinessLogic: 初始化Handler与线程");
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程启动");
if (mServiceHandler == null) {
mServiceHandler = new ControlCenterServiceHandler(this);
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler初始化完成");
} else {
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler已存在无需重复初始化");
}
restartRemindThreadSafely();
}
// ================================== 提醒线程管理(安全启停,并发保护)=================================
/**
* 安全重启提醒线程
*/
public void restartRemindThreadSafely() {
LogUtils.d(TAG, "restartRemindThreadSafely: 开始重启线程");
// 停止旧线程
stopRemindThreadSafely();
if (mServiceHandler == null) {
// 创建新线程实例
RemindThread.destroyInstance();
mRemindThread = RemindThread.getInstance(this, mServiceHandler);
syncConfigToRemindThread();
// 启动线程
if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
try {
mRemindThread.start();
LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功ID=" + mRemindThread.getId());
} catch (IllegalThreadStateException e) {
LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常", e);
mRemindThread = null;
}
} else {
LogUtils.w(TAG, "restartRemindThreadSafely: 线程状态异常,跳过启动");
}
} else {
LogUtils.d(TAG, "mServiceHandler is null");
}
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程结束");
}
/**
* 安全停止提醒线程
*/
private void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely: 停止提醒线程");
if (mRemindThread == null) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程实例为空");
return;
}
try {
if (mRemindThread.isThreadStarted() || mRemindThread.isAlive()) {
mRemindThread.setIsReminding(false);
mRemindThread.stopThread();
// 等待线程终止超时1秒强制中断
long waitStartTime = System.currentTimeMillis();
while (mRemindThread.isAlive()) {
if (System.currentTimeMillis() - waitStartTime > 1000) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程停止超时,强制中断");
mRemindThread.interrupt();
break;
}
Thread.yield();
}
}
} catch (Exception e) {
LogUtils.e(TAG, "stopRemindThreadSafely: 停止线程异常", e);
} finally {
mRemindThread = null;
RemindThread.destroyInstance();
}
}
/**
* 同步配置到提醒线程
*/
private void syncConfigToRemindThread() {
LogUtils.d(TAG, "syncConfigToRemindThread: 同步配置");
if (mRemindThread == null || mCurrentConfigBean == null) {
LogUtils.e(TAG, "syncConfigToRemindThread: 线程或配置为空,同步失败");
return;
}
mRemindThread.setAppConfigBean(mCurrentConfigBean);
mRemindThread.setIsReminding(true);
}
// ================================== 外部指令处理接收Intent指令=================================
/**
* 处理外部发送的服务指令
*/
// private void handleExternalCommand(Intent intent) {
// LogUtils.d(TAG, "handleExternalCommand: 处理外部指令");
// if (intent == null || TextUtils.isEmpty(intent.getAction())) {
// LogUtils.e(TAG, "handleExternalCommand: Intent或Action为空");
// return;
// }
// String action = intent.getAction();
// if (ACTION_RESTART_REMIND_THREAD.equals(action)) {
// synchronized (mServiceLock) {
// if (mServiceControlBean.isEnableService()) {
// AppConfigBean newConfig = (AppConfigBean) intent.getSerializableExtra(EXTRA_APP_CONFIG_BEAN);
// if (newConfig != null) {
// mCurrentConfigBean = newConfig;
// LogUtils.d(TAG, "handleExternalCommand: 收到配置更新,重启线程");
// restartRemindThreadSafely();
// } else {
// LogUtils.e(TAG, "handleExternalCommand: 配置为空,重启失败");
// }
// } else {
// LogUtils.w(TAG, "handleExternalCommand: 服务已禁用,忽略指令");
// }
// }
// }
// }
// ================================== 资源释放方法(防止内存泄漏)=================================
/**
* 停止前台服务
*/
private void stopForegroundService() {
LogUtils.d(TAG, "stopForegroundService: 停止前台服务");
if (mNotificationManager != null) {
mNotificationManager.cancelForegroundServiceNotify();
}
try {
stopForeground(STOP_FOREGROUND_REMOVE);
} catch (Exception e) {
LogUtils.e(TAG, "stopForegroundService: 停止前台状态异常", e);
}
}
/**
* 销毁Handler
* 销毁Handler移除所有消息和回调
*/
private void destroyHandler() {
LogUtils.d(TAG, "destroyHandler: 销毁Handler");
LogUtils.d(TAG, "destroyHandler: Handler销毁流程启动");
if (mServiceHandler != null) {
mServiceHandler.removeCallbacksAndMessages(null);
mServiceHandler = null;
LogUtils.d(TAG, "destroyHandler: Handler已销毁所有消息已移除");
} else {
LogUtils.w(TAG, "destroyHandler: Handler实例为空无需销毁");
}
LogUtils.d(TAG, "destroyHandler: Handler销毁流程结束");
}
/**
* 释放通知资源
*/
private void releaseNotificationResource() {
LogUtils.d(TAG, "releaseNotificationResource: 释放通知资源");
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放流程启动");
if (mNotificationManager != null) {
mNotificationManager.release();
mNotificationManager = null;
LogUtils.d(TAG, "releaseNotificationResource: 通知工具类资源释放完成");
} else {
LogUtils.w(TAG, "releaseNotificationResource: 通知工具类实例为空,无需释放");
}
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放流程结束");
}
/**
* 置空所有引用
* 置空所有引用,防止内存泄漏
*/
private void clearAllReferences() {
LogUtils.d(TAG, "clearAllReferences: 内存引用清理流程启动");
mForegroundNotifyMsg = null;
mCurrentConfigBean = null;
mServiceControlBean = null;
LogUtils.d(TAG, "clearAllReferences: 所有引用已置空");
LogUtils.d(TAG, "clearAllReferences: 所有业务引用已置空,防止内存泄漏");
LogUtils.d(TAG, "clearAllReferences: 内存引用清理流程结束");
}
// ================================== 静态工具方法(对外提供服务入口=================================
// ================================== 提醒线程管理(安全启停=================================
/**
* 安全重启提醒线程
*/
// public void restartRemindThreadSafely() {
// LogUtils.d(TAG, "restartRemindThreadSafely: 线程重启流程启动");
// // 停止旧线程
// stopRemindThreadSafely();
//
// if (mServiceHandler != null) {
// // 创建新线程实例
// RemindThread.destroyInstance();
// mRemindThread = RemindThread.getInstance(this, mServiceHandler);
// LogUtils.d(TAG, "restartRemindThreadSafely: RemindThread新实例创建完成 | 线程引用=" + mRemindThread);
// // 同步配置到线程
// syncConfigToRemindThread();
// // 启动线程
// if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
// try {
// mRemindThread.start();
// LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功 | 线程ID=" + mRemindThread.getId() + " | 线程名称=" + mRemindThread.getName());
// } catch (IllegalThreadStateException e) {
// LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常", e);
// mRemindThread = null;
// }
// } else {
// LogUtils.w(TAG, "restartRemindThreadSafely: 线程状态异常,跳过启动 | isAlive=" + (mRemindThread != null && mRemindThread.isAlive()) + " | isThreadStarted=" + (mRemindThread != null && mRemindThread.isThreadStarted()));
// }
// } else {
// LogUtils.e(TAG, "restartRemindThreadSafely: mServiceHandler is null线程启动失败");
// }
// LogUtils.d(TAG, "restartRemindThreadSafely: 线程重启流程结束");
// }
/**
* 安全停止提醒线程
*/
private void stopRemindThreadSafely() {
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止流程启动");
if (mRemindThread == null) {
LogUtils.w(TAG, "stopRemindThreadSafely: RemindThread实例为空跳过停止流程");
return;
}
try {
if (mRemindThread.isThreadStarted() || mRemindThread.isAlive()) {
LogUtils.d(TAG, "stopRemindThreadSafely: 线程处于运行状态,开始停止 | isThreadStarted=" + mRemindThread.isThreadStarted() + " | isAlive=" + mRemindThread.isAlive());
mRemindThread.setIsReminding(false);
mRemindThread.stopThread();
// 等待线程终止,超时强制中断
long waitStartTime = System.currentTimeMillis();
while (mRemindThread.isAlive()) {
if (System.currentTimeMillis() - waitStartTime > THREAD_STOP_TIMEOUT) {
LogUtils.w(TAG, "stopRemindThreadSafely: 线程停止超时(超时时间=" + THREAD_STOP_TIMEOUT + "ms强制中断");
mRemindThread.interrupt();
break;
}
Thread.yield();
}
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止完成,耗时=" + (System.currentTimeMillis() - waitStartTime) + "ms");
} else {
LogUtils.d(TAG, "stopRemindThreadSafely: 线程未运行,无需停止");
}
} catch (Exception e) {
LogUtils.e(TAG, "stopRemindThreadSafely: 停止线程异常", e);
} finally {
mRemindThread = null;
RemindThread.destroyInstance();
LogUtils.d(TAG, "stopRemindThreadSafely: 线程实例已置空,单例已销毁");
}
LogUtils.d(TAG, "stopRemindThreadSafely: 线程停止流程结束");
}
/**
* 同步配置到提醒线程
*/
private void syncConfigToRemindThread() {
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步流程启动");
if (mRemindThread == null || mCurrentConfigBean == null) {
LogUtils.e(TAG, "syncConfigToRemindThread: 配置同步失败 | mRemindThread=" + mRemindThread + " | mCurrentConfigBean=" + mCurrentConfigBean);
return;
}
mRemindThread.setAppConfigBean(mCurrentConfigBean);
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步成功 | 充电阈值=" + mCurrentConfigBean.getChargeReminderValue() + " | 耗电阈值=" + mCurrentConfigBean.getUsageReminderValue() + " | 检测间隔=" + mCurrentConfigBean.getBatteryDetectInterval() + "ms");
LogUtils.d(TAG, "syncConfigToRemindThread: 配置同步流程结束");
}
// ================================== 静态工具方法(对外提供服务入口,按功能归类)=================================
/**
* 启动服务
*/
public static void startControlCenterService(Context context) {
LogUtils.d(TAG, "startControlCenterService: 启动服务");
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用 =====");
if (context == null) {
LogUtils.e(TAG, "startControlCenterService: Context为空");
LogUtils.e(TAG, "startControlCenterService: Context为空,启动失败");
return;
}
// 保存服务启动配置
ControlCenterServiceBean.saveBean(context, new ControlCenterServiceBean(true));
// 保存服务启动配置
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(true);
ControlCenterServiceBean.saveBean(context, controlBean);
LogUtils.d(TAG, "startControlCenterService: 服务启动配置已保存 | 启用状态=" + controlBean.isEnableService());
// 构建启动Intent
Intent intent = new Intent(context, ControlCenterService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LogUtils.d(TAG, "startControlCenterService: SDK版本>=26调用startForegroundService启动前台服务");
context.startForegroundService(intent);
LogUtils.d(TAG, "startForegroundService 已调用");
} else {
LogUtils.d(TAG, "startControlCenterService: SDK版本<26调用startService启动普通服务");
context.startService(intent);
LogUtils.d(TAG, "startService 已调用");
}
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用完成 =====");
}
/**
* 停止服务
*/
public static void stopControlCenterService(Context context) {
LogUtils.d(TAG, "stopControlCenterService: 停止服务");
LogUtils.d(TAG, "===== stopControlCenterService: 外部停止服务接口调用 =====");
if (context == null) {
LogUtils.e(TAG, "stopControlCenterService: Context为空");
LogUtils.e(TAG, "stopControlCenterService: Context为空,停止失败");
return;
}
// 保存服务启动配置
ControlCenterServiceBean.saveBean(context, new ControlCenterServiceBean(false));
// 保存服务停止配置
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(context, controlBean);
LogUtils.d(TAG, "stopControlCenterService: 服务停止配置已保存 | 启用状态=" + controlBean.isEnableService());
// 构建停止Intent
Intent intent = new Intent(context, ControlCenterService.class);
LogUtils.d(TAG, "stopControlCenterService: 调用stopService发送停止指令");
context.stopService(intent);
LogUtils.d(TAG, "===== stopControlCenterService: 外部停止服务接口调用完成 =====");
}
/**
* 更新服务控制配置并启停服务
*/
// public static void updateServiceControlConfig(Context context, ControlCenterServiceBean controlBean) {
// LogUtils.d(TAG, "updateServiceControlConfig: 更新控制配置,启用状态=" + controlBean.isEnableService());
// if (context == null || controlBean == null) {
// LogUtils.e(TAG, "updateServiceControlConfig: 参数为空");
// return;
// }
// if (controlBean.isEnableService()) {
// startControlCenterService(context);
// } else {
// stopControlCenterService(context);
// }
// }
/**
* 更新业务配置并触发线程重启
*/
public static void updateStatus(Context context, AppConfigBean configBean) {
LogUtils.d(TAG, "updateStatus: 发送配置更新指令");
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用 =====");
if (context == null || configBean == null) {
LogUtils.e(TAG, "updateStatus: 参数为空");
LogUtils.e(TAG, "updateStatus: 参数为空 | context=" + context + " | configBean=" + configBean);
return;
}
LogUtils.d(TAG, "updateStatus: 待同步配置 | 充电阈值=" + configBean.getChargeReminderValue() + " | 耗电阈值=" + configBean.getUsageReminderValue());
// 构建配置更新Intent
Intent intent = new Intent(context, ControlCenterService.class);
intent.setAction(ACTION_RESTART_REMIND_THREAD);
intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
@@ -473,21 +423,26 @@ public class ControlCenterService extends Service {
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LogUtils.d(TAG, "updateStatus: SDK版本>=26调用startForegroundService发送配置更新指令");
context.startForegroundService(intent);
} else {
LogUtils.d(TAG, "updateStatus: SDK版本<26调用startService发送配置更新指令");
context.startService(intent);
}
LogUtils.d(TAG, "updateStatus: 配置更新指令发送成功");
} catch (Exception e) {
LogUtils.e(TAG, "updateStatus: 发送指令异常", e);
LogUtils.e(TAG, "updateStatus: 发送配置更新指令异常", e);
}
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用完成 =====");
}
/**
* 检查并引导用户开启忽略电池优化
*/
public static void checkIgnoreBatteryOptimization(Context context) {
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 检查电池优化状态");
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 电池优化检查流程启动");
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
LogUtils.w(TAG, "checkIgnoreBatteryOptimization: 无需检查 | context=" + context + " | SDK版本=" + (Build.VERSION.SDK_INT));
return;
}
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -496,32 +451,43 @@ public class ControlCenterService extends Service {
return;
}
try {
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
String packageName = context.getPackageName();
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 当前忽略电池优化状态=" + isIgnored);
if (!isIgnored) {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
intent.setData(Uri.parse("package:" + packageName));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化");
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已跳转至系统设置页,引导用户开启忽略电池优化");
} else {
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已开启忽略电池优化,无需引导");
}
} catch (Exception e) {
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导异常", e);
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化异常", e);
}
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 电池优化检查流程结束");
}
/**
* 判断服务是否运行适配API30+
*/
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程启动 | serviceClass=" + (serviceClass != null ? serviceClass.getName() : "null"));
if (context == null || serviceClass == null) {
LogUtils.e(TAG, "isServiceRunning: 参数为空 | context=" + context + " | serviceClass=" + serviceClass);
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
return false;
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) {
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败");
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
return false;
}
boolean isRunning = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
LogUtils.d(TAG, "isServiceRunning: SDK版本>=30使用进程信息判断");
String packageName = context.getPackageName();
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
if (processes != null) {
@@ -529,78 +495,86 @@ public class ControlCenterService extends Service {
if (packageName.equals(process.processName) &&
(process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE ||
process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)) {
return true;
isRunning = true;
LogUtils.d(TAG, "isServiceRunning: 检测到前台服务进程,判定服务运行");
break;
}
}
}
return isServiceStarted(context, serviceClass);
if (!isRunning) {
LogUtils.d(TAG, "isServiceRunning: API30+未检测到运行,执行兜底判断");
isRunning = isServiceStarted(context, serviceClass);
}
} else {
LogUtils.d(TAG, "isServiceRunning: SDK版本<30使用服务列表判断");
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);
if (runningServices != null) {
String serviceClassName = serviceClass.getName();
for (ActivityManager.RunningServiceInfo info : runningServices) {
if (serviceClassName.equals(info.service.getClassName())) {
return true;
isRunning = true;
LogUtils.d(TAG, "isServiceRunning: 检测到服务在运行列表中,判定服务运行");
break;
}
}
}
return false;
}
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=" + isRunning);
return isRunning;
}
/**
* 兜底判断服务是否已启动
*/
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程启动");
boolean result = false;
try {
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
return controlBean != null && controlBean.isEnableService();
result = controlBean != null && controlBean.isEnableService();
LogUtils.d(TAG, "isServiceStarted: 兜底判断结果=" + result + " | 配置启用状态=" + (controlBean != null ? controlBean.isEnableService() : "null"));
} catch (Exception e) {
LogUtils.e(TAG, "isServiceStarted: 兜底判断异常", e);
return false;
result = false;
}
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程结束 | 结果=" + result);
return result;
}
// ================================== Getter/Setter 方法(线程安全=================================
// ================================== Getter/Setter 方法(添加日志=================================
public RemindThread getRemindThread() {
return mRemindThread;
return mRemindThread;
}
public void setCurrentConfigBean(AppConfigBean configBean) {
LogUtils.d(TAG, "setCurrentConfigBean: 更新业务配置");
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新接口调用");
if (configBean == null) {
LogUtils.e(TAG, "setCurrentConfigBean: 配置为空");
LogUtils.e(TAG, "setCurrentConfigBean: 待更新配置为空,更新失败");
return;
}
this.mCurrentConfigBean = configBean;
syncConfigToRemindThread();
this.mCurrentConfigBean = configBean;
syncConfigToRemindThread();
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新完成 | 新充电阈值=" + configBean.getChargeReminderValue());
}
// public void setServiceControlBean(ControlCenterServiceBean controlBean) {
// LogUtils.d(TAG, "setServiceControlBean: 更新控制配置");
// if (controlBean != null) {
// updateAndSaveServiceControlConfig(controlBean);
// }
// }
public ControlCenterServiceBean getServiceControlBean() {
return mServiceControlBean;
return mServiceControlBean;
}
public NotificationManagerUtils getNotificationManager() {
return mNotificationManager;
return mNotificationManager;
}
public NotificationMessage getForegroundNotifyMsg() {
return mForegroundNotifyMsg;
return mForegroundNotifyMsg;
}
public AppConfigBean getCurrentConfigBean() {
return mCurrentConfigBean;
return mCurrentConfigBean;
}
public boolean isDestroyed() {
return mIsDestroyed;
return mIsDestroyed;
}
}

View File

@@ -8,79 +8,137 @@ import cc.winboll.studio.powerbell.models.AppConfigBean;
import java.lang.ref.WeakReference;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:38
* @Describe 提醒线程(单例模式):统一管理充电/耗电提醒逻辑,适配Java7+API30+,发送提醒时同步携带当前电量+充电状态
* 提醒线程(单例模式)
* 功能:统一管理充电/耗电提醒逻辑,发送提醒时携带当前电量+充电状态
* 适配Java7 | API30 | 小米手机
* 特性:线程安全、内存泄漏防护、配置重试兜底
* 对外接口:仅保留 {@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)} 和 {@link #stopRemindThread()}
*/
public class RemindThread extends Thread {
// ================================== 静态常量(置顶,统一管理魔法值)=================================
// ================================== 静态常量(置顶归类,消除魔法值)=================================
public static final String TAG = "RemindThread";
private static final long INIT_DELAY_TIME = 500L; // 初始化延迟ms等待服务就绪
private static final int MIN_SLEEP_TIME = 500; // 最小检测间隔ms防高频轮询
private static final int DEFAULT_SLEEP_TIME = 1000; // 默认检测间隔ms
private static final long REMIND_INTERVAL = 3000L; // 重复提醒间隔ms防骚扰
private static final int CONFIG_RETRY_MAX = 3; // 配置同步重试次数(兜底)
private static final int INVALID_BATTERY_VALUE = -1; // 无效电量标记
private static final long BACKGROUND_SLEEP_TIME = 5000L;// 后台休眠间隔ms减少资源占用
// ================================== 单例核心(线程安全,避免复用旧实例)=================================
// 时间常量 (ms)
private static final long INIT_DELAY_TIME = 500L;
private static final int MIN_SLEEP_TIME = 500;
private static final int DEFAULT_SLEEP_TIME = 1000;
private static final long REMIND_INTERVAL = 3000L;
// 重试与状态常量
private static final int CONFIG_RETRY_MAX = 3;
private static final int INVALID_BATTERY_VALUE = -1;
// ================================== 单例核心(线程安全,双重校验锁)=================================
private static volatile RemindThread sInstance;
// ================================== 成员变量(按功能分volatile+锁保护=================================
// 依赖资源(防内存泄漏)
// ================================== 成员变量(按功能分volatile保证多线程可见性,防内存泄漏=================================
// 弱引用依赖(避免内存泄漏)
private Context mContext;
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
// 线程状态(核心标记,多线程可见)
private volatile boolean isExist; // 退出标记true=退出)
private volatile boolean isThreadStarted; // 启动标记区分isAlive()
private volatile boolean isReminding; // 全局提醒开关
private volatile boolean isRemindTimerRunning; // 提醒恢复计时器状态
// 线程状态标记volatile 保证多线程可见
private volatile boolean isExist;
private volatile boolean isThreadStarted;
private volatile boolean isReminding;
private volatile boolean isRemindTimerRunning;
// 业务配置(实时同步,范围校验
private volatile boolean isEnableChargeReminder; // 充电提醒开关
private volatile boolean isEnableUsageReminder; // 耗电提醒开关
private volatile long sleepTime; // 检测间隔ms改为long适配大间隔
private volatile int chargeReminderValue; // 充电提醒阈值0-100
private volatile int usageReminderValue; // 耗电提醒阈值0-100
private volatile int quantityOfElectricity; // 当前电量0-100无效为-1
private volatile boolean isCharging; // 充电状态标记
// 业务配置参数(范围校验,实时同步
private volatile boolean isEnableChargeReminder;
private volatile boolean isEnableUsageReminder;
private volatile long sleepTime;
private volatile int chargeReminderValue;
private volatile int usageReminderValue;
private volatile int quantityOfElectricity;
private volatile boolean isCharging;
// 辅助变量(并发安全+防重复提醒)
private volatile long lastRemindTime; // 上次提醒时间戳ms
private final Object mLock = new Object(); // 全局锁(保护所有状态变量)
private volatile long lastRemindTime;
private final Object mLock = new Object();
// ================================== 私有构造器(单例专用,初始化状态+防护泄漏)=================================
private RemindThread(Context context, ControlCenterServiceHandler handler) {
LogUtils.d(TAG, "构造线程实例,线程名称:" + getName());
this.mContext = context.getApplicationContext();
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
resetThreadStateInternal(); // 初始化所有状态,避免脏数据
resetThreadStateInternal();
LogUtils.d(TAG, "构造线程实例 | threadName=" + getName() + " | threadId=" + getId());
}
// ================================== 单例管理(获取+销毁,彻底释放资源=================================
// ================================== 对外公开静态方法(仅保留两个:启动+停止=================================
/**
* 获取单例实例(旧线程停止自动销毁,强制入参校验)
* 对外启动线程接口
* @param context 上下文
* @param handler 服务处理器
* @param config 应用配置Bean
* @return 若 isReminding 为 true 直接返回 true否则创建/启动线程后返回 false
*/
public static RemindThread getInstance(Context context, ControlCenterServiceHandler handler) {
LogUtils.d(TAG, "获取单例,当前实例是否存在:" + (sInstance != null));
if (context == null || handler == null) {
LogUtils.e(TAG, "致命错误Context/ControlCenterServiceHandler不能为空");
throw new IllegalArgumentException("Context and ControlCenterServiceHandler cannot be null");
public static boolean startRemindThread(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
// 入参校验
if (context == null || handler == null || config == null) {
LogUtils.e(TAG, "startRemindThread: 入参为空,启动失败");
return false;
}
// 旧线程停止则销毁,确保新实例有效
if (sInstance != null && !sInstance.isRunning()) {
destroyInstance();
LogUtils.d(TAG, "旧线程已停止,销毁单例准备创建新实例");
// 1. 若 isReminding 为真,直接返回 true 无需操作
if (sInstance != null && sInstance.isReminding) {
LogUtils.d(TAG, "startRemindThread: isReminding为true直接返回");
return true;
}
// 双重校验锁创建单例
// 2. 未创建实例则创建
if (sInstance == null) {
synchronized (RemindThread.class) {
if (sInstance == null) {
sInstance = new RemindThread(context, handler);
LogUtils.d(TAG, "新线程实例创建成功线程ID" + sInstance.getId());
}
}
}
// 3. 同步配置
sInstance.setAppConfigBean(config);
// 4. 线程未运行则启动
if (!sInstance.isRunning()) {
sInstance.isExist = false; // 重置退出标记
sInstance.start();
LogUtils.d(TAG, "startRemindThread: 线程启动成功 | threadId=" + sInstance.getId());
} else {
LogUtils.d(TAG, "startRemindThread: 线程已在运行 | threadId=" + sInstance.getId());
}
return false;
}
/**
* 对外停止线程接口:直接销毁单例
*/
public static void stopRemindThread() {
LogUtils.d(TAG, "stopRemindThread: 开始停止线程");
destroyInstance();
LogUtils.d(TAG, "stopRemindThread: 线程已停止并销毁");
}
// ================================== 私有单例管理方法(内部使用)=================================
/**
* 获取单例实例(私有化,仅内部调用)
*/
private static RemindThread getInstance(Context context, ControlCenterServiceHandler handler) {
LogUtils.d(TAG, "getInstance: 尝试获取单例 | currentInstance=" + (sInstance != null ? "存在" : "不存在"));
if (context == null || handler == null) {
LogUtils.e(TAG, "getInstance: 入参为空");
throw new IllegalArgumentException("Context and ControlCenterServiceHandler cannot be null");
}
if (sInstance != null && !sInstance.isRunning()) {
destroyInstance();
LogUtils.d(TAG, "getInstance: 旧线程已停止,销毁单例");
}
if (sInstance == null) {
synchronized (RemindThread.class) {
if (sInstance == null) {
sInstance = new RemindThread(context, handler);
LogUtils.d(TAG, "getInstance: 新线程实例创建成功 | threadId=" + sInstance.getId());
}
}
}
@@ -90,201 +148,213 @@ public class RemindThread extends Thread {
/**
* 销毁单例(安全停止线程+释放资源,避免内存泄漏)
*/
public static void destroyInstance() {
LogUtils.d(TAG, "开始销毁线程单例");
private static void destroyInstance() {
LogUtils.d(TAG, "destroyInstance: 开始销毁线程单例");
synchronized (RemindThread.class) {
if (sInstance != null) {
sInstance.stopThread();
sInstance.releaseResources();
sInstance.isExist = true;
sInstance.isReminding = false;
sInstance.isRemindTimerRunning = false;
if (sInstance.isAlive()) {
sInstance.interrupt();
LogUtils.d(TAG, "destroyInstance: 线程已中断");
}
sInstance.releaseResourcesInternal();
sInstance = null;
LogUtils.d(TAG, "线程单例销毁完成");
LogUtils.d(TAG, "destroyInstance: 线程单例销毁完成");
} else {
LogUtils.w(TAG, "单例已为空,跳过销毁");
LogUtils.w(TAG, "destroyInstance: 单例已为空,跳过销毁");
}
}
}
// ================================== 线程核心逻辑run方法高效退出+异常容错)=================================
// ================================== 线程核心逻辑run方法高效退出+异常容错仅此处保留mLock=================================
@Override
public void run() {
LogUtils.d(TAG, "线程启动ID" + Thread.currentThread().getId() + ",状态:" + getState());
// 防止run方法重复执行
LogUtils.d(TAG, "run: 线程启动 | threadId=" + Thread.currentThread().getId() + " | state=" + getState());
// 仅保留此处的mLock保护isReminding等核心状态的读写防止线程重复启动
synchronized (mLock) {
if (isThreadStarted || isExist) {
LogUtils.e(TAG, "线程已启动/待退出禁止重复执行run");
LogUtils.e(TAG, "run: 线程重复启动 | isThreadStarted=" + isThreadStarted + " | isExist=" + isExist);
return;
}
isThreadStarted = true;
lastRemindTime = 0;
// 确保isReminding初始状态正确
isReminding = isEnableChargeReminder || isEnableUsageReminder;
}
// 配置同步重试(失败则兜底默认值)
boolean configValid = syncConfigRetry();
if (!configValid) {
LogUtils.e(TAG, "配置同步失败,使用默认阈值兜底启动");
LogUtils.e(TAG, "run: 配置同步失败,使用兜底阈值启动");
}
// 初始化延迟(等待服务就绪)
try {
LogUtils.d(TAG, "初始化延迟" + INIT_DELAY_TIME + "ms");
LogUtils.d(TAG, "run: 初始化延迟 | delayTime=" + INIT_DELAY_TIME + "ms");
Thread.sleep(INIT_DELAY_TIME);
if (isExist) {
LogUtils.d(TAG, "延迟期间收到退出指令,线程终止");
cleanThreadState();
LogUtils.d(TAG, "run: 延迟期间收到退出指令,线程终止");
cleanThreadStateInternal();
return;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.e(TAG, "初始化延迟被中断,线程终止", e);
cleanThreadState();
LogUtils.e(TAG, "run: 初始化延迟被中断,线程终止", e);
cleanThreadStateInternal();
return;
}
// ===================== 新增:首次电量检测,立即触发符合条件的提醒 =====================
LogUtils.d(TAG, "run: 执行首次电量检测");
if (!isExist && isReminding && quantityOfElectricity != INVALID_BATTERY_VALUE) {
// 充电提醒:充电中 + 充电提醒开启 + 电量≥阈值
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "run: 首次检测触发充电提醒 | battery=" + quantityOfElectricity + " ≥ threshold=" + chargeReminderValue);
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
lastRemindTime = System.currentTimeMillis();
startRemindRecoveryTimerInternal();
}
// 耗电提醒:未充电 + 耗电提醒开启 + 电量≤阈值
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "run: 首次检测触发耗电提醒 | battery=" + quantityOfElectricity + " ≤ threshold=" + usageReminderValue);
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
lastRemindTime = System.currentTimeMillis();
startRemindRecoveryTimerInternal();
}
}
// 核心检测循环(快速退出+并发安全)
LogUtils.d(TAG, "进入电量检测循环,间隔:" + sleepTime + "ms");
LogUtils.d(TAG, "run: 进入电量检测循环 | sleepTime=" + sleepTime + "ms");
while (!isExist) {
try {
if (isExist) break;
// 核心防护:提醒关闭/电量无效,直接休眠(跳过提醒检测
synchronized (mLock) {
// 提醒关闭/电量无效:正常休眠,不检测
if (!isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
safeSleep(sleepTime);
continue;
}
// 电量超出范围:修正为无效,休眠重试
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
LogUtils.w(TAG, "电量无效(" + quantityOfElectricity + "),标记为无效值");
quantityOfElectricity = INVALID_BATTERY_VALUE;
safeSleep(sleepTime);
continue;
}
// 核心防护:提醒关闭/电量无效,直接休眠(依赖volatile保证可见性
if (!isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
safeSleepInternal(sleepTime);
continue;
}
// 电量超出范围:修正为无效值
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
LogUtils.w(TAG, "run: 电量无效,修正为无效值 | currentBattery=" + quantityOfElectricity);
quantityOfElectricity = INVALID_BATTERY_VALUE;
safeSleepInternal(sleepTime);
continue;
}
// 锁保护核心提醒逻辑(仅提醒开启+电量有效时执行
synchronized (mLock) {
if (isExist || !isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
safeSleep(sleepTime);
continue;
}
// 防重复提醒(间隔未到/计时器运行中)
long currentTime = System.currentTimeMillis();
if ((currentTime - lastRemindTime < REMIND_INTERVAL) || isRemindTimerRunning) {
safeSleep(sleepTime);
continue;
}
// 充电提醒触发(携带当前电量+充电状态发送)
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "触发充电提醒:充电中,电量" + quantityOfElectricity + "≥阈值" + chargeReminderValue);
sendNotificationMessage("+", quantityOfElectricity, isCharging);
lastRemindTime = currentTime;
startRemindRecoveryTimer();
}
// 耗电提醒触发(携带当前电量+充电状态发送)
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "触发耗电提醒:未充电,电量" + quantityOfElectricity + "≤阈值" + usageReminderValue);
sendNotificationMessage("-", quantityOfElectricity, isCharging);
lastRemindTime = currentTime;
startRemindRecoveryTimer();
}
// 防重复提醒(间隔未到/计时器运行中依赖volatile保证可见性
long currentTime = System.currentTimeMillis();
if ((currentTime - lastRemindTime < REMIND_INTERVAL) || isRemindTimerRunning) {
safeSleepInternal(sleepTime);
continue;
}
safeSleep(sleepTime);
// 充电提醒触发
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
LogUtils.d(TAG, "run: 循环检测触发充电提醒 | battery=" + quantityOfElectricity + " ≥ threshold=" + chargeReminderValue);
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
lastRemindTime = currentTime;
startRemindRecoveryTimerInternal();
}
// 耗电提醒触发
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "run: 循环检测触发耗电提醒 | battery=" + quantityOfElectricity + " ≤ threshold=" + usageReminderValue);
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
lastRemindTime = currentTime;
startRemindRecoveryTimerInternal();
}
safeSleepInternal(sleepTime);
} catch (Exception e) {
LogUtils.e(TAG, "线程运行异常,休眠重试", e);
safeSleep(sleepTime);
LogUtils.e(TAG, "run: 线程运行异常,休眠重试", e);
safeSleepInternal(sleepTime);
}
}
// 退出清理
cleanThreadState();
LogUtils.d(TAG, "线程循环退出ID" + Thread.currentThread().getId());
cleanThreadStateInternal();
LogUtils.d(TAG, "run: 线程循环退出 | threadId=" + Thread.currentThread().getId());
}
// ================================== 核心业务辅助方法(配置同步+消息发送+计时器=================================
// ================================== 核心业务辅助方法(全部私有化,移除对外访问=================================
/**
* 配置同步重试(确保阈值有效,失败兜底)
*/
private boolean syncConfigRetry() {
LogUtils.d(TAG, "syncConfigRetry: 开始配置同步 | maxRetry=" + CONFIG_RETRY_MAX);
int retryCount = 0;
while (retryCount < CONFIG_RETRY_MAX) {
synchronized (mLock) {
if ((chargeReminderValue >= 0 && chargeReminderValue <= 100)
&& (usageReminderValue >= 0 && usageReminderValue <= 100)) {
LogUtils.d(TAG, "配置同步成功,重试次数:" + retryCount);
return true;
}
boolean chargeValid = chargeReminderValue >= 0 && chargeReminderValue <= 100;
boolean usageValid = usageReminderValue >= 0 && usageReminderValue <= 100;
if (chargeValid && usageValid) {
LogUtils.d(TAG, "syncConfigRetry: 配置同步成功 | retryCount=" + retryCount);
return true;
}
LogUtils.w(TAG, "配置未同步,重试次数:" + (retryCount + 1));
LogUtils.w(TAG, "syncConfigRetry: 配置未同步,重试 | retryCount=" + (retryCount + 1));
try {
Thread.sleep(1000);
retryCount++;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.e(TAG, "配置重试被中断", e);
LogUtils.e(TAG, "syncConfigRetry: 配置重试被中断", e);
return false;
}
}
// 兜底默认阈值(避免无效值触发提醒)
synchronized (mLock) {
chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
quantityOfElectricity = INVALID_BATTERY_VALUE; // 兜底电量设为无效,防止误触发
LogUtils.e(TAG, "配置重试失败,兜底阈值:充电" + chargeReminderValue + ",耗电" + usageReminderValue + "RuntimeException : Config sync failed.");
}
// 兜底默认阈值
chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
quantityOfElectricity = INVALID_BATTERY_VALUE;
LogUtils.e(TAG, "syncConfigRetry: 配置重试失败,使用兜底阈值 | chargeThreshold=" + chargeReminderValue + " | usageThreshold=" + usageReminderValue);
return false;
}
/**
* 发送提醒消息(携带当前电量+充电状态弱引用Handler+Message复用防泄漏
* @param type 提醒类型(+:充电提醒,-:耗电提醒)
* @param battery 当前电量0-100
* @param isCharging 当前充电状态true=充电中)
*/
private void sendNotificationMessage(String type, int battery, boolean isCharging) {
LogUtils.d(TAG, "准备发送提醒消息:类型=" + type + ",电量=" + battery + ",充电状态=" + 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, "线程退出/提醒关闭,跳过发送");
LogUtils.d(TAG, "sendNotificationMessageInternal: 线程退出提醒关闭,跳过发送");
return;
}
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler != null ? mwrControlCenterServiceHandler.get() : null;
if (handler == null) {
LogUtils.w(TAG, "Handler已回收发送失败");
LogUtils.w(TAG, "sendNotificationMessageInternal: Handler已回收发送失败");
return;
}
// 构建消息what=提醒标识obj=类型arg1=当前电量arg2=充电状态0=未充电1=充电中)
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT);
message.obj = type;
message.arg1 = battery;
message.arg2 = isCharging ? 1 : 0; // boolean转int兼容Java7
message.arg2 = isCharging ? 1 : 0;
try {
handler.sendMessage(message);
LogUtils.d(TAG, "提醒消息发送成功:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
LogUtils.d(TAG, "sendNotificationMessageInternal: 提醒消息发送成功");
} catch (Exception e) {
LogUtils.e(TAG, "消息发送异常", e);
LogUtils.e(TAG, "sendNotificationMessageInternal: 消息发送异常", e);
if (message != null) message.recycle();
}
}
/**
* 启动提醒恢复计时器(防重复提醒,弱引用线程+锁保护
* 启动提醒恢复计时器(防重复提醒,弱引用线程)
*/
private void startRemindRecoveryTimer() {
LogUtils.d(TAG, "启动提醒恢复计时器,间隔:" + REMIND_INTERVAL + "ms");
synchronized (mLock) {
if (isExist || isRemindTimerRunning || sInstance != this) {
LogUtils.w(TAG, "计时器启动条件不满足,跳过");
return;
}
isReminding = false;
isRemindTimerRunning = true;
private void startRemindRecoveryTimerInternal() {
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 启动提醒恢复计时器 | interval=" + REMIND_INTERVAL + "ms");
if (isExist || isRemindTimerRunning || sInstance != this) {
LogUtils.w(TAG, "startRemindRecoveryTimerInternal: 计时器启动条件不满足");
return;
}
isReminding = false;
isRemindTimerRunning = true;
final WeakReference<RemindThread> threadRef = new WeakReference<>(this);
new Thread(new Runnable() {
@@ -293,323 +363,136 @@ public class RemindThread extends Thread {
try {
Thread.sleep(REMIND_INTERVAL);
RemindThread thread = threadRef.get();
if (thread == null || thread.isExist || sInstance != thread) {
LogUtils.d(TAG, "线程已销毁,不恢复提醒");
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 线程已销毁,不恢复提醒");
return;
}
synchronized (thread.mLock) {
// 仅线程存活+有启用提醒时,才恢复提醒
if (!thread.isExist && sInstance == thread
&& (thread.isEnableChargeReminder || thread.isEnableUsageReminder)) {
thread.isReminding = true;
LogUtils.d(TAG, "提醒功能恢复开启");
}
boolean canRecover = !thread.isExist && sInstance == thread && (thread.isEnableChargeReminder || thread.isEnableUsageReminder);
if (canRecover) {
thread.isReminding = true;
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒功能恢复开启");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.e(TAG, "计时器被中断", e);
LogUtils.e(TAG, "startRemindRecoveryTimerInternal: 计时器被中断", e);
} finally {
RemindThread thread = threadRef.get();
if (thread != null) {
synchronized (thread.mLock) {
if (sInstance == thread) thread.isRemindTimerRunning = false;
}
if (thread != null && sInstance == thread) {
thread.isRemindTimerRunning = false;
}
LogUtils.d(TAG, "提醒恢复计时器执行完成");
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒恢复计时器执行完成");
}
}
}, "RemindRecoveryTimer").start();
}
// ================================== 线程控制方法(停止+休眠+状态清理)=================================
/**
* 安全停止线程(快速退出+中断休眠)
*/
public void stopThread() {
LogUtils.d(TAG, "开始停止线程,当前状态:" + getState());
synchronized (mLock) {
isExist = true;
isReminding = false;
isRemindTimerRunning = false;
}
if (isAlive()) {
interrupt();
LogUtils.d(TAG, "线程已中断,加速退出");
}
if (sInstance == this) sInstance = null;
}
/**
* 废弃方法统一用stopThread
*/
@Deprecated
public void forceStopThread() {
LogUtils.w(TAG, "forceStopThread已废弃请调用stopThread");
stopThread();
}
/**
* 安全休眠(保留中断标记,确保退出逻辑生效)
*/
private void safeSleep(long millis) {
private void safeSleepInternal(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LogUtils.w(TAG, "休眠被中断,线程准备退出");
LogUtils.w(TAG, "safeSleepInternal: 休眠被中断,线程准备退出");
}
}
/**
* 清理线程运行状态(退出后重置所有标记)
*/
private void cleanThreadState() {
LogUtils.d(TAG, "清理线程运行状态");
synchronized (mLock) {
isReminding = false;
isExist = true;
isThreadStarted = false;
isRemindTimerRunning = false;
lastRemindTime = 0;
quantityOfElectricity = INVALID_BATTERY_VALUE; // 重置为无效电量,防残留
}
private void cleanThreadStateInternal() {
LogUtils.d(TAG, "cleanThreadStateInternal: 清理线程运行状态");
isReminding = false;
isExist = true;
isThreadStarted = false;
isRemindTimerRunning = false;
lastRemindTime = 0;
quantityOfElectricity = INVALID_BATTERY_VALUE;
if (isAlive()) interrupt();
if (sInstance == this) sInstance = null;
}
// ================================== 状态重置方法(初始化+运行时重置)=================================
/**
* 初始状态重置(构造器专用)
*/
private void resetThreadStateInternal() {
LogUtils.d(TAG, "重置线程初始状态");
synchronized (mLock) {
// 线程状态
isExist = false;
isReminding = false;
isThreadStarted = false;
isRemindTimerRunning = false;
lastRemindTime = 0;
// 业务配置
isEnableChargeReminder = false;
isEnableUsageReminder = false;
sleepTime = DEFAULT_SLEEP_TIME;
chargeReminderValue = -1;
usageReminderValue = -1;
quantityOfElectricity = INVALID_BATTERY_VALUE; // 初始设为无效
isCharging = false;
}
LogUtils.d(TAG, "resetThreadStateInternal: 重置线程初始状态");
isExist = false;
isReminding = false;
isThreadStarted = false;
isRemindTimerRunning = false;
lastRemindTime = 0;
isEnableChargeReminder = false;
isEnableUsageReminder = false;
sleepTime = DEFAULT_SLEEP_TIME;
chargeReminderValue = -1;
usageReminderValue = -1;
quantityOfElectricity = INVALID_BATTERY_VALUE;
isCharging = false;
}
/**
* 运行时状态重置(外部调用,不重置配置)
*/
public void resetThreadState() {
LogUtils.d(TAG, "重置线程运行状态");
synchronized (mLock) {
isExist = false;
isRemindTimerRunning = false;
lastRemindTime = 0;
isReminding = (isEnableChargeReminder || isEnableUsageReminder); // 根据开关自动开启提醒
}
LogUtils.d(TAG, "运行状态重置完成,全局提醒:" + isReminding);
}
// ================================== 配置同步方法(完整同步配置,原子操作+无效电量防护)=================================
/**
* 同步应用配置(参数校验+范围限制,立即生效)
*/
public void setAppConfigBean(AppConfigBean config) {
LogUtils.d(TAG, "setAppConfigBean: 开始同步应用配置 | config=" + config);
if (config == null) {
LogUtils.e(TAG, "配置Bean为空同步失败");
synchronized (mLock) {
quantityOfElectricity = INVALID_BATTERY_VALUE; // 配置为空,标记电量无效
}
LogUtils.e(TAG, "setAppConfigBean: 配置Bean为空同步失败");
quantityOfElectricity = INVALID_BATTERY_VALUE;
return;
}
LogUtils.d(TAG, "开始同步配置:充电阈值" + config.getChargeReminderValue() + ",耗电阈值" + config.getUsageReminderValue() + ",当前电量" + config.getCurrentBatteryValue());
synchronized (mLock) {
// 同步开关
isEnableChargeReminder = config.isEnableChargeReminder();
isEnableUsageReminder = config.isEnableUsageReminder();
// 同步阈值0-100限制
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
// 同步检测间隔(≥最小间隔)
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
// 同步电池状态(校验有效,无效则标记为-1
int currentBattery = config.getCurrentBatteryValue();
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
isCharging = config.isCharging();
// 提醒开关:根据配置自动开启
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
}
LogUtils.d(TAG, "配置同步完成:检测间隔" + sleepTime + "ms全局提醒" + isReminding + ",当前电量" + quantityOfElectricity);
isEnableChargeReminder = config.isEnableChargeReminder();
isEnableUsageReminder = config.isEnableUsageReminder();
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
int currentBattery = config.getCurrentBatteryValue();
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
isCharging = config.isCharging();
isReminding = isEnableChargeReminder || isEnableUsageReminder;
LogUtils.d(TAG, "setAppConfigBean: 配置同步完成 | sleepTime=" + sleepTime + "ms | isReminding=" + isReminding + " | currentBattery=" + quantityOfElectricity);
}
// ================================== Setter/Getter锁保护线程安全+精准日志)=================================
public boolean isExist() {
synchronized (mLock) {
return isExist;
}
/**
* 判断线程是否处于运行状态
*/
private boolean isRunning() {
boolean running = !isExist && isThreadStarted && isAlive();
LogUtils.d(TAG, "isRunning: 线程运行状态=" + running + " | isExist=" + isExist + " | isThreadStarted=" + isThreadStarted + " | isAlive=" + isAlive());
return running;
}
public void setIsExist(boolean isExist) {
synchronized (mLock) {
this.isExist = isExist;
LogUtils.d(TAG, "设置线程退出标记:" + isExist);
/**
* 释放线程所有资源(内部方法)
*/
private void releaseResourcesInternal() {
LogUtils.d(TAG, "releaseResourcesInternal: 开始释放线程资源");
mContext = null;
if (mwrControlCenterServiceHandler != null) {
mwrControlCenterServiceHandler.clear();
mwrControlCenterServiceHandler = null;
}
cleanThreadStateInternal();
LogUtils.d(TAG, "releaseResourcesInternal: 线程资源释放完成");
}
public boolean isReminding() {
synchronized (mLock) {
return isReminding;
}
}
public void setIsReminding(boolean isReminding) {
synchronized (mLock) {
this.isReminding = isReminding;
LogUtils.d(TAG, "设置全局提醒开关:" + this.isReminding);
}
}
public boolean isThreadStarted() {
synchronized (mLock) {
return isThreadStarted;
}
}
public boolean isEnableUsageReminder() {
synchronized (mLock) {
return isEnableUsageReminder;
}
}
public void setIsEnableUsageReminder(boolean isEnableUsageReminder) {
synchronized (mLock) {
this.isEnableUsageReminder = isEnableUsageReminder;
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
LogUtils.d(TAG, "设置耗电提醒开关:" + isEnableUsageReminder + ",全局提醒:" + isReminding);
}
}
public boolean isEnableChargeReminder() {
synchronized (mLock) {
return isEnableChargeReminder;
}
}
public void setIsEnableChargeReminder(boolean isEnableChargeReminder) {
synchronized (mLock) {
this.isEnableChargeReminder = isEnableChargeReminder;
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
LogUtils.d(TAG, "设置充电提醒开关:" + isEnableChargeReminder + ",全局提醒:" + isReminding);
}
}
public long getSleepTime() {
synchronized (mLock) {
return sleepTime;
}
}
public void setSleepTime(long sleepTime) {
synchronized (mLock) {
this.sleepTime = Math.max(sleepTime, MIN_SLEEP_TIME);
LogUtils.d(TAG, "设置检测间隔:" + this.sleepTime + "ms");
}
}
public int getChargeReminderValue() {
synchronized (mLock) {
return chargeReminderValue;
}
}
public void setChargeReminderValue(int chargeReminderValue) {
synchronized (mLock) {
this.chargeReminderValue = Math.min(Math.max(chargeReminderValue, 0), 100);
LogUtils.d(TAG, "设置充电提醒阈值:" + this.chargeReminderValue);
}
}
public int getUsageReminderValue() {
synchronized (mLock) {
return usageReminderValue;
}
}
public void setUsageReminderValue(int usageReminderValue) {
synchronized (mLock) {
this.usageReminderValue = Math.min(Math.max(usageReminderValue, 0), 100);
LogUtils.d(TAG, "设置耗电提醒阈值:" + this.usageReminderValue);
}
}
public int getQuantityOfElectricity() {
synchronized (mLock) {
return quantityOfElectricity;
}
}
public void setQuantityOfElectricity(int quantityOfElectricity) {
synchronized (mLock) {
this.quantityOfElectricity = Math.min(Math.max(quantityOfElectricity, 0), 100);
LogUtils.d(TAG, "更新当前电量:" + this.quantityOfElectricity);
}
}
public boolean isCharging() {
synchronized (mLock) {
return isCharging;
}
}
public void setIsCharging(boolean isCharging) {
synchronized (mLock) {
this.isCharging = isCharging;
LogUtils.d(TAG, "更新充电状态:" + isCharging);
}
}
// ================================== 核心状态判断Service依赖精准校验=================================
public boolean isRunning() {
synchronized (mLock) {
boolean running = !isExist && isThreadStarted && isAlive();
LogUtils.d(TAG, "线程运行状态:" + running + "(退出:" + isExist + ",已启动:" + isThreadStarted + ",存活:" + isAlive() + "");
return running;
}
}
// ================================== 资源释放(彻底断开引用,防内存泄漏)=================================
public void releaseResources() {
LogUtils.d(TAG, "开始释放线程资源");
synchronized (mLock) {
mContext = null;
if (mwrControlCenterServiceHandler != null) {
mwrControlCenterServiceHandler.clear();
mwrControlCenterServiceHandler = null;
}
cleanThreadState();
}
LogUtils.d(TAG, "线程资源释放完成");
}
// ================================== 调试辅助toString打印核心状态=================================
// ================================== 调试辅助toString 私有化,避免对外暴露状态)=================================
@Override
public String toString() {
return "RemindThread{" +
"threadId=" + getId() +
", threadName='" + getName() + '\'' +
", isRunning=" + isRunning() +
", isReminding=" + isReminding() +
", chargeThreshold=" + getChargeReminderValue() +
", usageThreshold=" + getUsageReminderValue() +
", currentBattery=" + getQuantityOfElectricity() +
", isCharging=" + isCharging() +
", sleepTime=" + getSleepTime() + "ms" +
", isReminding=" + isReminding +
", chargeThreshold=" + chargeReminderValue +
", usageThreshold=" + usageReminderValue +
", currentBattery=" + quantityOfElectricity +
", isCharging=" + isCharging +
", sleepTime=" + sleepTime + "ms" +
'}';
}
}