服务线程调试中,目标就是线程放入服务类使用handler与服务通信。
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user