服务线程调试中,目标就是线程放入服务类使用handler与服务通信。
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#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
|
stageCount=10
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.14
|
baseVersion=15.14
|
||||||
publishVersion=15.14.9
|
publishVersion=15.14.9
|
||||||
buildCount=35
|
buildCount=42
|
||||||
baseBetaVersion=15.14.10
|
baseBetaVersion=15.14.10
|
||||||
|
|||||||
@@ -45,43 +45,42 @@ import cc.winboll.studio.powerbell.views.MainContentView;
|
|||||||
* @Date 2025/12/17 13:14
|
* @Date 2025/12/17 13:14
|
||||||
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
|
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
|
||||||
* 适配:Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
|
* 适配:Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
|
||||||
* 核心规则:UI开关仅管理本地配置,服务启停仅在应用启动时根据配置执行
|
* 核心规则:UI开关直接联动服务启停,本地配置与服务状态实时同步
|
||||||
*/
|
*/
|
||||||
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
|
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
|
||||||
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
|
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
|
||||||
public static final String TAG = "MainActivity";
|
public static final String TAG = "MainActivity";
|
||||||
// 请求码
|
// 请求码
|
||||||
private static final int REQUEST_READ_MEDIA_IMAGES = 1001; // 背景设置请求码
|
private static final int REQUEST_READ_MEDIA_IMAGES = 1001;
|
||||||
// 延迟时间
|
// 延迟时间
|
||||||
private static final int DELAY_LOAD_NON_CRITICAL = 500; // 非核心视图延迟加载(ms)
|
private static final long DELAY_LOAD_NON_CRITICAL = 500L;
|
||||||
// Handler消息标识(按业务优先级排序)
|
// Handler消息标识(按业务优先级排序)
|
||||||
public static final int MSG_RELOAD_APPCONFIG = 0; // 重新加载配置
|
public static final int MSG_RELOAD_APPCONFIG = 0;
|
||||||
public static final int MSG_CURRENTVALUEBATTERY = 1; // 更新当前电量
|
public static final int MSG_CURRENTVALUEBATTERY = 1;
|
||||||
public static final int MSG_LOAD_BACKGROUND = 2; // 加载背景
|
public static final int MSG_LOAD_BACKGROUND = 2;
|
||||||
private static final int MSG_RESTART_REMIND_THREAD = 3; // 重启RemindThread线程
|
private static final int MSG_START_REMIND_THREAD = 3;
|
||||||
private static final int MSG_UPDATE_SERVICE_SWITCH = 4; // 更新服务开关UI
|
private static final int MSG_UPDATE_SERVICE_SWITCH = 4;
|
||||||
|
|
||||||
// ======================== 静态成员(全局共享,严格管控生命周期)========================
|
// ======================== 静态成员(全局共享,严格管控生命周期)========================
|
||||||
private static MainActivity sMainActivity; // 全局Activity实例(销毁时必须置空)
|
private static MainActivity sMainActivity;
|
||||||
private static Handler sGlobalHandler; // 全局Handler(统一消息分发)
|
private static Handler sGlobalHandler;
|
||||||
|
|
||||||
// ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减)========================
|
// ======================== 工具类实例(单例,避免重复初始化)========================
|
||||||
// 工具类实例(单例,避免重复初始化)
|
|
||||||
private PermissionUtils mPermissionUtils;
|
private PermissionUtils mPermissionUtils;
|
||||||
private AppConfigUtils mAppConfigUtils;
|
private AppConfigUtils mAppConfigUtils;
|
||||||
private BackgroundSourceUtils mBgSourceUtils;
|
private BackgroundSourceUtils mBgSourceUtils;
|
||||||
// 应用核心实例
|
|
||||||
|
// ======================== 应用核心实例 =========================
|
||||||
private App mApplication;
|
private App mApplication;
|
||||||
private MainContentView mMainContentView; // 核心视图封装类
|
private MainContentView mMainContentView;
|
||||||
// 基础视图组件
|
private ControlCenterServiceBean mServiceControlBean;
|
||||||
|
|
||||||
|
// ======================== 基础视图组件 =========================
|
||||||
private Toolbar mToolbar;
|
private Toolbar mToolbar;
|
||||||
private ViewStub mAdsViewStub;
|
private ViewStub mAdsViewStub;
|
||||||
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
|
private ADsBannerView mADsBannerView;
|
||||||
// 资源与菜单
|
private Drawable mFrameDrawable;
|
||||||
private Menu mMenu;
|
private Menu mMenu;
|
||||||
private Drawable mFrameDrawable; // 框架背景资源
|
|
||||||
// 服务控制核心Bean
|
|
||||||
private ControlCenterServiceBean mServiceControlBean;
|
|
||||||
|
|
||||||
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
|
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
|
||||||
@Override
|
@Override
|
||||||
@@ -96,83 +95,79 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
LogUtils.d(TAG, "onCreate: 进入");
|
LogUtils.d(TAG, "onCreate: start");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
// 1. 初始化全局Handler(优先初始化,避免消息丢失)
|
// 优先初始化全局Handler,避免消息丢失
|
||||||
initGlobalHandler();
|
initGlobalHandler();
|
||||||
// 2. 加载布局+初始化核心流程
|
// 布局与核心流程初始化
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
initPermissionUtils();
|
initPermissionUtils();
|
||||||
initMainContentView();
|
initMainContentView();
|
||||||
initCriticalView();
|
initCriticalView();
|
||||||
initCoreUtilsAsync();
|
initCoreUtilsAsync();
|
||||||
loadNonCriticalViewDelayed();
|
loadNonCriticalViewDelayed();
|
||||||
LogUtils.d(TAG, "onCreate: 退出");
|
LogUtils.d(TAG, "onCreate: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostCreate(Bundle savedInstanceState) {
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
LogUtils.d(TAG, "onPostCreate: 进入");
|
LogUtils.d(TAG, "onPostCreate: start");
|
||||||
super.onPostCreate(savedInstanceState);
|
super.onPostCreate(savedInstanceState);
|
||||||
mPermissionUtils.startPermissionRequest(this);
|
mPermissionUtils.startPermissionRequest(this);
|
||||||
LogUtils.d(TAG, "onPostCreate: 退出");
|
LogUtils.d(TAG, "onPostCreate: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
LogUtils.d(TAG, "onResume: 进入");
|
LogUtils.d(TAG, "onResume: start");
|
||||||
super.onResume();
|
super.onResume();
|
||||||
// 恢复背景+同步服务开关UI(仅本地配置)
|
// 恢复背景与服务开关UI
|
||||||
if (sGlobalHandler != null) {
|
if (sGlobalHandler != null) {
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||||
LogUtils.d(TAG, "onResume: 发送背景加载+服务开关更新消息");
|
LogUtils.d(TAG, "onResume: send MSG_LOAD_BACKGROUND & MSG_UPDATE_SERVICE_SWITCH");
|
||||||
}
|
}
|
||||||
// 恢复广告
|
// 恢复广告
|
||||||
if (mADsBannerView != null) {
|
if (mADsBannerView != null) {
|
||||||
mADsBannerView.resumeADs(this);
|
mADsBannerView.resumeADs(this);
|
||||||
}
|
}
|
||||||
// // 设置RemindThread前台状态
|
LogUtils.d(TAG, "onResume: end");
|
||||||
// setRemindThreadForeground(true);
|
|
||||||
LogUtils.d(TAG, "onResume: 退出");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
LogUtils.d(TAG, "onPause: 进入");
|
LogUtils.d(TAG, "onPause: start");
|
||||||
super.onPause();
|
super.onPause();
|
||||||
// // 设置RemindThread后台状态
|
LogUtils.d(TAG, "onPause: end");
|
||||||
// setRemindThreadForeground(false);
|
|
||||||
LogUtils.d(TAG, "onPause: 退出");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
LogUtils.d(TAG, "onDestroy: 进入");
|
LogUtils.d(TAG, "onDestroy: start");
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
// 1. 释放广告资源
|
// 释放广告资源
|
||||||
if (mADsBannerView != null) {
|
if (mADsBannerView != null) {
|
||||||
mADsBannerView.releaseAdResources();
|
mADsBannerView.releaseAdResources();
|
||||||
mADsBannerView = null;
|
mADsBannerView = null;
|
||||||
}
|
}
|
||||||
// 2. 释放核心视图资源
|
// 释放核心视图
|
||||||
if (mMainContentView != null) {
|
if (mMainContentView != null) {
|
||||||
mMainContentView.releaseResources();
|
mMainContentView.releaseResources();
|
||||||
mMainContentView = null;
|
mMainContentView = null;
|
||||||
}
|
}
|
||||||
// 3. 销毁线程+清理Handler
|
// 销毁线程与Handler
|
||||||
RemindThread.destroyInstance();
|
RemindThread.stopRemindThread();
|
||||||
if (sGlobalHandler != null) {
|
if (sGlobalHandler != null) {
|
||||||
sGlobalHandler.removeCallbacksAndMessages(null);
|
sGlobalHandler.removeCallbacksAndMessages(null);
|
||||||
sGlobalHandler = null;
|
sGlobalHandler = null;
|
||||||
}
|
}
|
||||||
// 4. 释放Drawable+置空全局实例
|
// 释放Drawable,防止内存泄漏
|
||||||
if (mFrameDrawable != null) {
|
if (mFrameDrawable != null) {
|
||||||
mFrameDrawable.setCallback(null);
|
mFrameDrawable.setCallback(null);
|
||||||
mFrameDrawable = null;
|
mFrameDrawable = null;
|
||||||
}
|
}
|
||||||
|
// 置空所有引用
|
||||||
sMainActivity = null;
|
sMainActivity = null;
|
||||||
// 5. 置空所有辅助实例
|
|
||||||
mPermissionUtils = null;
|
mPermissionUtils = null;
|
||||||
mAppConfigUtils = null;
|
mAppConfigUtils = null;
|
||||||
mBgSourceUtils = null;
|
mBgSourceUtils = null;
|
||||||
@@ -181,27 +176,24 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
mApplication = null;
|
mApplication = null;
|
||||||
mToolbar = null;
|
mToolbar = null;
|
||||||
mAdsViewStub = null;
|
mAdsViewStub = null;
|
||||||
LogUtils.d(TAG, "onDestroy: 退出");
|
LogUtils.d(TAG, "onDestroy: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
LogUtils.d(TAG, "onActivityResult: 进入,requestCode=" + requestCode + ",resultCode=" + resultCode);
|
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode);
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
|
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
|
||||||
// 背景设置完成后重新加载背景
|
// 背景设置完成后重新加载
|
||||||
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
|
if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) {
|
||||||
if (sGlobalHandler != null) {
|
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "onActivityResult: 退出");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================== 菜单与导航方法 ========================
|
// ======================== 菜单与导航方法 ========================
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
LogUtils.d(TAG, "onCreateOptionsMenu: 进入");
|
LogUtils.d(TAG, "onCreateOptionsMenu: start");
|
||||||
mMenu = menu;
|
mMenu = menu;
|
||||||
AESThemeUtil.inflateMenu(this, menu);
|
AESThemeUtil.inflateMenu(this, menu);
|
||||||
if (App.isDebugging()) {
|
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_unittest, mMenu);
|
||||||
}
|
}
|
||||||
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
|
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
|
||||||
LogUtils.d(TAG, "onCreateOptionsMenu: 退出");
|
LogUtils.d(TAG, "onCreateOptionsMenu: end");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
LogUtils.d(TAG, "onOptionsItemSelected: 进入,itemId=" + item.getItemId());
|
LogUtils.d(TAG, "onOptionsItemSelected: itemId=" + item.getItemId());
|
||||||
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
|
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
|
||||||
recreate();
|
recreate();
|
||||||
return true;
|
return true;
|
||||||
@@ -245,7 +237,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "onOptionsItemSelected: 退出");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +251,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
moveTaskToBack(true);
|
moveTaskToBack(true);
|
||||||
LogUtils.d(TAG, "onBackPressed: 应用退到后台");
|
LogUtils.d(TAG, "onBackPressed: app move to background");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -270,26 +261,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
|
|
||||||
// ======================== 核心初始化方法 ========================
|
// ======================== 核心初始化方法 ========================
|
||||||
private void initPermissionUtils() {
|
private void initPermissionUtils() {
|
||||||
LogUtils.d(TAG, "initPermissionUtils: 进入");
|
LogUtils.d(TAG, "initPermissionUtils: start");
|
||||||
mPermissionUtils = PermissionUtils.getInstance();
|
mPermissionUtils = PermissionUtils.getInstance();
|
||||||
LogUtils.d(TAG, "initPermissionUtils: 退出");
|
LogUtils.d(TAG, "initPermissionUtils: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化全局Handler(核心优化:弱引用+生命周期校验,杜绝内存泄漏)
|
|
||||||
*/
|
|
||||||
private void initGlobalHandler() {
|
private void initGlobalHandler() {
|
||||||
LogUtils.d(TAG, "initGlobalHandler: 进入");
|
LogUtils.d(TAG, "initGlobalHandler: start");
|
||||||
if (sGlobalHandler == null) {
|
if (sGlobalHandler == null) {
|
||||||
sGlobalHandler = new Handler() {
|
sGlobalHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
// 严格校验Activity状态,避免销毁后操作UI
|
// 校验Activity状态,避免销毁后操作UI
|
||||||
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
|
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
|
||||||
LogUtils.w(TAG, "handleMessage: Activity已销毁,跳过消息处理");
|
LogUtils.w(TAG, "handleMessage: Activity destroyed, skip msg what=" + msg.what);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "handleMessage: 接收消息,what=" + msg.what);
|
LogUtils.d(TAG, "handleMessage: receive msg what=" + msg.what);
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_RELOAD_APPCONFIG:
|
case MSG_RELOAD_APPCONFIG:
|
||||||
sMainActivity.updateViewData();
|
sMainActivity.updateViewData();
|
||||||
@@ -303,32 +291,30 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
sMainActivity.reloadBackground();
|
sMainActivity.reloadBackground();
|
||||||
sMainActivity.setMainLayoutBackgroundColor();
|
sMainActivity.setMainLayoutBackgroundColor();
|
||||||
break;
|
break;
|
||||||
case MSG_RESTART_REMIND_THREAD:
|
case MSG_START_REMIND_THREAD:
|
||||||
AppConfigBean configBean = (AppConfigBean) msg.obj;
|
AppConfigBean configBean = (AppConfigBean) msg.obj;
|
||||||
sMainActivity.restartRemindThread(configBean);
|
LogUtils.d(TAG, "MSG_START_REMIND_THREAD not yet.");
|
||||||
break;
|
break;
|
||||||
case MSG_UPDATE_SERVICE_SWITCH:
|
case MSG_UPDATE_SERVICE_SWITCH:
|
||||||
sMainActivity.updateServiceSwitchUI();
|
sMainActivity.updateServiceSwitchUI();
|
||||||
break;
|
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() {
|
private void initMainContentView() {
|
||||||
LogUtils.d(TAG, "initMainContentView: 进入");
|
LogUtils.d(TAG, "initMainContentView: start");
|
||||||
View rootView = findViewById(android.R.id.content);
|
View rootView = findViewById(android.R.id.content);
|
||||||
mMainContentView = new MainContentView(this, rootView, this);
|
mMainContentView = new MainContentView(this, rootView, this);
|
||||||
LogUtils.d(TAG, "initMainContentView: 核心视图封装类初始化完成");
|
LogUtils.d(TAG, "initMainContentView: MainContentView created");
|
||||||
LogUtils.d(TAG, "initMainContentView: 退出");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initCriticalView() {
|
private void initCriticalView() {
|
||||||
LogUtils.d(TAG, "initCriticalView: 进入");
|
LogUtils.d(TAG, "initCriticalView: start");
|
||||||
sMainActivity = this;
|
sMainActivity = this;
|
||||||
mToolbar = findViewById(R.id.toolbar);
|
mToolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(mToolbar);
|
setSupportActionBar(mToolbar);
|
||||||
@@ -336,81 +322,75 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
|
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
|
||||||
}
|
}
|
||||||
mAdsViewStub = findViewById(R.id.stub_ads_banner);
|
mAdsViewStub = findViewById(R.id.stub_ads_banner);
|
||||||
LogUtils.d(TAG, "initCriticalView: 退出");
|
LogUtils.d(TAG, "initCriticalView: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步初始化核心工具类(保留服务启停逻辑:应用启动时根据配置执行)
|
|
||||||
*/
|
|
||||||
private void initCoreUtilsAsync() {
|
private void initCoreUtilsAsync() {
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 进入");
|
LogUtils.d(TAG, "initCoreUtilsAsync: start");
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
|
LogUtils.d(TAG, "initCoreUtilsAsync: async thread start");
|
||||||
mApplication = (App) getApplication();
|
mApplication = (App) getApplication();
|
||||||
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
|
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
|
||||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
|
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
|
||||||
|
|
||||||
// 初始化服务控制Bean(优先读取本地配置,无则创建默认)
|
// 初始化服务控制配置
|
||||||
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
|
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
|
||||||
if (mServiceControlBean == null) {
|
if (mServiceControlBean == null) {
|
||||||
mServiceControlBean = new ControlCenterServiceBean(false);
|
mServiceControlBean = new ControlCenterServiceBean(false);
|
||||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 创建默认服务控制配置(禁用)");
|
LogUtils.d(TAG, "initCoreUtilsAsync: create default service config (disabled)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用启动时:根据本地配置执行服务启停(仅执行一次)
|
// 根据配置启停服务
|
||||||
if (mServiceControlBean.isEnableService()) {
|
final boolean isServiceEnable = mServiceControlBean.isEnableService();
|
||||||
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
|
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
|
||||||
|
if (isServiceEnable && !isServiceAlive) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ControlCenterService.startControlCenterService(getApplicationContext());
|
ControlCenterService.startControlCenterService(getApplicationContext());
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置启动服务");
|
LogUtils.d(TAG, "initCoreUtilsAsync: start service by config");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else if (!isServiceEnable && isServiceAlive) {
|
||||||
} else {
|
|
||||||
if (ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
|
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ControlCenterService.stopControlCenterService(getApplicationContext());
|
ControlCenterService.stopControlCenterService(getApplicationContext());
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置停止服务");
|
LogUtils.d(TAG, "initCoreUtilsAsync: stop service by config");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 切换主线程更新UI
|
// 主线程更新UI
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isFinishing() || isDestroyed()) {
|
if (isFinishing() || isDestroyed()) {
|
||||||
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁,跳过UI更新");
|
LogUtils.w(TAG, "initCoreUtilsAsync: Activity destroyed, skip UI update");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 适配API30+主题加载Drawable
|
// 加载框架背景
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
|
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
|
||||||
} else {
|
} else {
|
||||||
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame);
|
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame);
|
||||||
}
|
}
|
||||||
// 执行核心业务
|
|
||||||
updateViewData();
|
updateViewData();
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
|
LogUtils.d(TAG, "initCoreUtilsAsync: async thread end");
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
LogUtils.d(TAG, "initCoreUtilsAsync: 退出");
|
LogUtils.d(TAG, "initCoreUtilsAsync: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadNonCriticalViewDelayed() {
|
private void loadNonCriticalViewDelayed() {
|
||||||
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入");
|
LogUtils.d(TAG, "loadNonCriticalViewDelayed: start");
|
||||||
new Handler().postDelayed(new Runnable() {
|
new Handler().postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -420,38 +400,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
loadAdsView();
|
loadAdsView();
|
||||||
}
|
}
|
||||||
}, DELAY_LOAD_NON_CRITICAL);
|
}, DELAY_LOAD_NON_CRITICAL);
|
||||||
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出");
|
LogUtils.d(TAG, "loadNonCriticalViewDelayed: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 视图操作方法 ========================
|
// ======================== 视图操作方法 ========================
|
||||||
private void loadAdsView() {
|
private void loadAdsView() {
|
||||||
LogUtils.d(TAG, "loadAdsView: 进入");
|
LogUtils.d(TAG, "loadAdsView: start");
|
||||||
if (mAdsViewStub == null) {
|
if (mAdsViewStub == null) {
|
||||||
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空");
|
LogUtils.e(TAG, "loadAdsView: AdsViewStub is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mADsBannerView == null) {
|
if (mADsBannerView == null) {
|
||||||
View adsView = mAdsViewStub.inflate();
|
View adsView = mAdsViewStub.inflate();
|
||||||
mADsBannerView = adsView.findViewById(R.id.adsbanner);
|
mADsBannerView = adsView.findViewById(R.id.adsbanner);
|
||||||
|
LogUtils.d(TAG, "loadAdsView: ADsBannerView created");
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "loadAdsView: 退出");
|
LogUtils.d(TAG, "loadAdsView: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateViewData() {
|
private void updateViewData() {
|
||||||
LogUtils.d(TAG, "updateViewData: 进入");
|
LogUtils.d(TAG, "updateViewData: start");
|
||||||
if (mMainContentView == null || mFrameDrawable == null) {
|
if (mMainContentView == null || mFrameDrawable == null) {
|
||||||
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空");
|
LogUtils.e(TAG, "updateViewData: MainContentView or FrameDrawable is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mMainContentView.updateViewData(mFrameDrawable);
|
mMainContentView.updateViewData(mFrameDrawable);
|
||||||
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
|
LogUtils.d(TAG, "updateViewData: view data updated");
|
||||||
LogUtils.d(TAG, "updateViewData: 退出");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadBackground() {
|
private void reloadBackground() {
|
||||||
LogUtils.d(TAG, "reloadBackground: 进入");
|
LogUtils.d(TAG, "reloadBackground: start");
|
||||||
if (mMainContentView == null || mBgSourceUtils == null) {
|
if (mMainContentView == null || mBgSourceUtils == null) {
|
||||||
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空");
|
LogUtils.e(TAG, "reloadBackground: MainContentView or BackgroundSourceUtils is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||||
@@ -460,133 +440,114 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
} else {
|
} else {
|
||||||
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
|
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "reloadBackground: 退出");
|
LogUtils.d(TAG, "reloadBackground: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMainLayoutBackgroundColor() {
|
private void setMainLayoutBackgroundColor() {
|
||||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入");
|
LogUtils.d(TAG, "setMainLayoutBackgroundColor: start");
|
||||||
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
|
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
|
||||||
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效");
|
LogUtils.e(TAG, "setMainLayoutBackgroundColor: invalid context");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||||
if (currentBgBean != null) {
|
if (currentBgBean != null) {
|
||||||
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
|
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出");
|
LogUtils.d(TAG, "setMainLayoutBackgroundColor: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新服务开关UI(仅同步本地配置,不校验服务状态)
|
|
||||||
*/
|
|
||||||
private void updateServiceSwitchUI() {
|
private void updateServiceSwitchUI() {
|
||||||
LogUtils.d(TAG, "updateServiceSwitchUI: 进入");
|
LogUtils.d(TAG, "updateServiceSwitchUI: start");
|
||||||
if (mMainContentView == null || mServiceControlBean == null) {
|
if (mMainContentView == null || mServiceControlBean == null) {
|
||||||
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空");
|
LogUtils.e(TAG, "updateServiceSwitchUI: MainContentView or ServiceControlBean is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 仅读取本地配置状态,不涉及服务状态校验
|
|
||||||
boolean configEnabled = mServiceControlBean.isEnableService();
|
boolean configEnabled = mServiceControlBean.isEnableService();
|
||||||
LogUtils.d(TAG, "updateServiceSwitchUI: 本地配置状态=" + configEnabled);
|
LogUtils.d(TAG, "updateServiceSwitchUI: config enabled=" + configEnabled);
|
||||||
|
|
||||||
// 仅更新UI开关状态
|
|
||||||
mMainContentView.setServiceSwitchEnabled(false);
|
mMainContentView.setServiceSwitchEnabled(false);
|
||||||
mMainContentView.setServiceSwitchChecked(configEnabled);
|
mMainContentView.setServiceSwitchChecked(configEnabled);
|
||||||
mMainContentView.setServiceSwitchEnabled(true);
|
mMainContentView.setServiceSwitchEnabled(true);
|
||||||
LogUtils.d(TAG, "updateServiceSwitchUI: 退出");
|
LogUtils.d(TAG, "updateServiceSwitchUI: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 服务与线程管理方法 ========================
|
// ======================== 服务与线程管理方法 ========================
|
||||||
/**
|
// private void restartRemindThread(AppConfigBean configBean) {
|
||||||
* 重启提醒线程(仅由配置变更触发,不与UI开关联动)
|
// LogUtils.d(TAG, "restartRemindThread: start, configBean=" + configBean);
|
||||||
*/
|
// if (configBean == null || mServiceControlBean == null) {
|
||||||
private void restartRemindThread(AppConfigBean configBean) {
|
// LogUtils.e(TAG, "restartRemindThread: configBean or ServiceControlBean is null");
|
||||||
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: 服务未运行,跳过状态设置");
|
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// try {
|
// if (!mServiceControlBean.isEnableService()) {
|
||||||
// RemindThread.getInstance(getApplicationContext(), null).setAppForeground(isForeground);
|
// LogUtils.w(TAG, "restartRemindThread: service is disabled, skip");
|
||||||
// } catch (IllegalArgumentException e) {
|
// return;
|
||||||
// LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化", e);
|
|
||||||
// }
|
// }
|
||||||
// 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) {
|
private void toggleServiceEnableState(boolean isEnable) {
|
||||||
LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable);
|
LogUtils.d(TAG, "toggleServiceEnableState: target state=" + isEnable);
|
||||||
if (mServiceControlBean == null) {
|
if (mServiceControlBean == null) {
|
||||||
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空");
|
LogUtils.e(TAG, "toggleServiceEnableState: ServiceControlBean is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 仅更新本地配置并持久化
|
|
||||||
mServiceControlBean.setIsEnableService(isEnable);
|
mServiceControlBean.setIsEnableService(isEnable);
|
||||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
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);
|
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||||
LogUtils.d(TAG, "toggleServiceEnableState: 退出");
|
LogUtils.d(TAG, "toggleServiceEnableState: config saved + service state synced");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 页面跳转方法 ========================
|
// ======================== 页面跳转方法 ========================
|
||||||
private void startAboutActivity() {
|
private void startAboutActivity() {
|
||||||
LogUtils.d(TAG, "startAboutActivity: 进入");
|
LogUtils.d(TAG, "startAboutActivity: start");
|
||||||
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
|
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
|
||||||
APPInfo appInfo = genDefaultAppInfo();
|
APPInfo appInfo = genDefaultAppInfo();
|
||||||
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
|
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
|
||||||
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
|
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
|
||||||
LogUtils.d(TAG, "startAboutActivity: 退出");
|
LogUtils.d(TAG, "startAboutActivity: end");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 消息发送方法 ========================
|
// ======================== 消息发送方法 ========================
|
||||||
private void sendRestartRemindThreadMessage() {
|
private void sendRestartRemindThreadMessage() {
|
||||||
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入");
|
LogUtils.d(TAG, "sendRestartRemindThreadMessage: start");
|
||||||
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
|
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
|
||||||
LogUtils.e(TAG, "sendRestartRemindThreadMessage: 环境无效");
|
LogUtils.e(TAG, "sendRestartRemindThreadMessage: invalid context");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD);
|
Message msg = sGlobalHandler.obtainMessage(MSG_START_REMIND_THREAD);
|
||||||
msg.obj = mAppConfigUtils.mAppConfigBean;
|
msg.obj = mAppConfigUtils.mAppConfigBean;
|
||||||
sGlobalHandler.sendMessage(msg);
|
sGlobalHandler.sendMessage(msg);
|
||||||
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出");
|
LogUtils.d(TAG, "sendRestartRemindThreadMessage: msg sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 静态工具方法 ========================
|
// ======================== 静态工具方法 ========================
|
||||||
public static void reloadAppConfig() {
|
public static void reloadAppConfig() {
|
||||||
LogUtils.d(TAG, "reloadAppConfig: 发送配置更新消息");
|
LogUtils.d(TAG, "reloadAppConfig: send MSG_RELOAD_APPCONFIG");
|
||||||
if (sGlobalHandler != null) {
|
if (sGlobalHandler != null) {
|
||||||
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
|
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendCurrentBatteryValueMessage(int value) {
|
public static void sendCurrentBatteryValueMessage(int value) {
|
||||||
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value);
|
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: battery=" + value);
|
||||||
if (sGlobalHandler != null) {
|
if (sGlobalHandler != null) {
|
||||||
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
|
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
|
||||||
msg.arg1 = value;
|
msg.arg1 = value;
|
||||||
@@ -596,9 +557,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
|
|
||||||
// ======================== 辅助工具方法 ========================
|
// ======================== 辅助工具方法 ========================
|
||||||
private String getRealPathFromUri(Uri contentUri) {
|
private String getRealPathFromUri(Uri contentUri) {
|
||||||
LogUtils.d(TAG, "getRealPathFromUri: 进入");
|
LogUtils.d(TAG, "getRealPathFromUri: uri=" + contentUri);
|
||||||
if (contentUri == null) {
|
if (contentUri == null) {
|
||||||
LogUtils.e(TAG, "getRealPathFromUri: URI为空");
|
LogUtils.e(TAG, "getRealPathFromUri: Uri is null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String realPath = null;
|
String realPath = null;
|
||||||
@@ -616,12 +577,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "getRealPathFromUri: 退出,路径=" + realPath);
|
LogUtils.d(TAG, "getRealPathFromUri: path=" + realPath);
|
||||||
return realPath;
|
return realPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private APPInfo genDefaultAppInfo() {
|
private APPInfo genDefaultAppInfo() {
|
||||||
LogUtils.d(TAG, "genDefaultAppInfo: 进入");
|
LogUtils.d(TAG, "genDefaultAppInfo: start");
|
||||||
String branchName = "powerbell";
|
String branchName = "powerbell";
|
||||||
APPInfo appInfo = new APPInfo();
|
APPInfo appInfo = new APPInfo();
|
||||||
appInfo.setAppName(getString(R.string.app_name));
|
appInfo.setAppName(getString(R.string.app_name));
|
||||||
@@ -634,39 +595,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
|||||||
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
|
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
|
||||||
appInfo.setAppAPKName("PowerBell");
|
appInfo.setAppAPKName("PowerBell");
|
||||||
appInfo.setAppAPKFolderName("PowerBell");
|
appInfo.setAppAPKFolderName("PowerBell");
|
||||||
LogUtils.d(TAG, "genDefaultAppInfo: 退出");
|
LogUtils.d(TAG, "genDefaultAppInfo: end");
|
||||||
return appInfo;
|
return appInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== MainContentView 事件回调 ========================
|
// ======================== MainContentView 事件回调 ========================
|
||||||
@Override
|
@Override
|
||||||
public void onChargeReminderSwitchChanged(boolean isChecked) {
|
public void onChargeReminderSwitchChanged(boolean isChecked) {
|
||||||
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 状态=" + isChecked);
|
LogUtils.d(TAG, "onChargeReminderSwitchChanged: isChecked=" + isChecked);
|
||||||
sendRestartRemindThreadMessage();
|
sendRestartRemindThreadMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUsageReminderSwitchChanged(boolean isChecked) {
|
public void onUsageReminderSwitchChanged(boolean isChecked) {
|
||||||
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 状态=" + isChecked);
|
LogUtils.d(TAG, "onUsageReminderSwitchChanged: isChecked=" + isChecked);
|
||||||
sendRestartRemindThreadMessage();
|
sendRestartRemindThreadMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceSwitchChanged(boolean isChecked) {
|
public void onServiceSwitchChanged(boolean isChecked) {
|
||||||
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
|
LogUtils.d(TAG, "onServiceSwitchChanged: isChecked=" + isChecked);
|
||||||
// 仅更新本地配置,不触发服务启停
|
|
||||||
toggleServiceEnableState(isChecked);
|
toggleServiceEnableState(isChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChargeReminderProgressChanged(int progress) {
|
public void onChargeReminderProgressChanged(int progress) {
|
||||||
LogUtils.d(TAG, "onChargeReminderProgressChanged: 进度=" + progress);
|
LogUtils.d(TAG, "onChargeReminderProgressChanged: progress=" + progress);
|
||||||
sendRestartRemindThreadMessage();
|
sendRestartRemindThreadMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUsageReminderProgressChanged(int progress) {
|
public void onUsageReminderProgressChanged(int progress) {
|
||||||
LogUtils.d(TAG, "onUsageReminderProgressChanged: 进度=" + progress);
|
LogUtils.d(TAG, "onUsageReminderProgressChanged: progress=" + progress);
|
||||||
sendRestartRemindThreadMessage();
|
sendRestartRemindThreadMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,19 +216,15 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
// 先同步完整配置(核心:setAppConfigBean已包含状态同步,无需重复设置)
|
// 先同步完整配置(核心:setAppConfigBean已包含状态同步,无需重复设置)
|
||||||
remindThread.setAppConfigBean(config);
|
remindThread.setAppConfigBean(config);
|
||||||
// 额外同步实时状态(兜底,确保最新)
|
//
|
||||||
remindThread.setIsCharging(isCharging);
|
//
|
||||||
remindThread.setQuantityOfElectricity(batteryLevel);
|
// // 线程未运行时唤醒,已运行时无需操作(避免重复唤醒导致逻辑紊乱)
|
||||||
// 确保线程开启提醒功能
|
// if (!remindThread.isRunning()) {
|
||||||
remindThread.setIsReminding(true);
|
// 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");
|
LogUtils.d(TAG, "updateRemindThreadConfig: success, thread config updated");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "updateRemindThreadConfig: failed", e);
|
LogUtils.e(TAG, "updateRemindThreadConfig: failed", e);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package cc.winboll.studio.powerbell.services;
|
package cc.winboll.studio.powerbell.services;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -10,11 +9,8 @@ import android.os.Build;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.R;
|
|
||||||
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
||||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||||
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||||
@@ -30,13 +26,15 @@ import java.util.List;
|
|||||||
* @Describe 电池提醒核心服务:修复前台服务超时异常,优先在onCreate发送通知,适配Java7+API30
|
* @Describe 电池提醒核心服务:修复前台服务超时异常,优先在onCreate发送通知,适配Java7+API30
|
||||||
*/
|
*/
|
||||||
public class ControlCenterService extends Service {
|
public class ControlCenterService extends Service {
|
||||||
// ================================== 静态常量(置顶统一管理,避免魔法值)=================================
|
// ================================== 静态常量(置顶统一管理,消除魔法值)=================================
|
||||||
public static final String TAG = "ControlCenterService";
|
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 ACTION_RESTART_REMIND_THREAD = "cc.winboll.studio.powerbell.action.RESTART_REMIND_THREAD";
|
||||||
public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
|
public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
|
||||||
|
// 超时常量
|
||||||
|
private static final long THREAD_STOP_TIMEOUT = 1000L;
|
||||||
|
|
||||||
// ================================== 成员变量(按功能分类,私有封装+并发锁保护)=================================
|
// ================================== 成员变量(按功能分类,私有封装)=================================
|
||||||
// 服务控制核心
|
// 服务控制核心
|
||||||
private ControlCenterServiceBean mServiceControlBean;
|
private ControlCenterServiceBean mServiceControlBean;
|
||||||
// 业务核心组件
|
// 业务核心组件
|
||||||
@@ -45,184 +43,164 @@ public class ControlCenterService extends Service {
|
|||||||
private NotificationManagerUtils mNotificationManager;
|
private NotificationManagerUtils mNotificationManager;
|
||||||
private AppConfigBean mCurrentConfigBean;
|
private AppConfigBean mCurrentConfigBean;
|
||||||
private NotificationMessage mForegroundNotifyMsg;
|
private NotificationMessage mForegroundNotifyMsg;
|
||||||
// 状态标记(复用 isServiceRunning 替代原 isCoreBusinessStarted)
|
// 状态标记(volatile保证多线程可见性)
|
||||||
private static volatile boolean isServiceRunning;
|
private static volatile boolean isServiceRunning;
|
||||||
private static volatile boolean mIsDestroyed;
|
private static volatile boolean mIsDestroyed;
|
||||||
|
|
||||||
// ================================== 服务生命周期方法(核心流程入口)=================================
|
// ================================== 服务生命周期方法(核心流程入口,按执行顺序排列)=================================
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
LogUtils.d(TAG, "onCreate: 服务开始创建");
|
LogUtils.d(TAG, "===== onCreate: 服务生命周期启动 =====");
|
||||||
|
LogUtils.d(TAG, "onCreate: 当前线程=" + Thread.currentThread().getName() + " | 进程ID=" + android.os.Process.myPid());
|
||||||
// 调用抽取的核心运行函数
|
|
||||||
runCoreServiceLogic();
|
runCoreServiceLogic();
|
||||||
LogUtils.d(TAG, "onCreate: 服务创建完成,前台通知已发送,启用状态=" + mServiceControlBean.isEnableService());
|
LogUtils.d(TAG, "===== onCreate: 服务生命周期结束 | 前台通知状态=" + (isServiceRunning ? "✅已发送" : "❌未发送") + " | 启用状态=" + (mServiceControlBean != null ? mServiceControlBean.isEnableService() : false) + " =====");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
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();
|
loadLatestServiceControlConfig();
|
||||||
// 调用抽取的核心运行函数
|
|
||||||
runCoreServiceLogic();
|
runCoreServiceLogic();
|
||||||
|
|
||||||
if (mServiceControlBean.isEnableService()) {
|
int returnFlag;
|
||||||
LogUtils.d(TAG, "onStartCommand: 服务已启用,返回START_STICKY");
|
if (mServiceControlBean != null && mServiceControlBean.isEnableService()) {
|
||||||
return START_STICKY;
|
LogUtils.d(TAG, "onStartCommand: 服务已启用,返回START_STICKY(被杀死后自动重启)");
|
||||||
|
returnFlag = START_STICKY;
|
||||||
} else {
|
} else {
|
||||||
return super.onStartCommand(intent, flags, startId);
|
LogUtils.d(TAG, "onStartCommand: 服务未启用,返回默认值");
|
||||||
|
returnFlag = super.onStartCommand(intent, flags, startId);
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "===== onStartCommand: 服务启动指令处理完成 | 返回值=" + returnFlag + " =====");
|
||||||
|
return returnFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程启动 =====");
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
LogUtils.d(TAG, "onDestroy: 服务开始销毁");
|
|
||||||
|
|
||||||
// 顺序释放资源
|
// 顺序释放资源
|
||||||
stopForegroundService();
|
stopForegroundService();
|
||||||
stopRemindThreadSafely();
|
stopRemindThreadSafely();
|
||||||
destroyHandler();
|
destroyHandler();
|
||||||
releaseNotificationResource();
|
releaseNotificationResource();
|
||||||
clearAllReferences();
|
clearAllReferences();
|
||||||
|
// 重置核心状态标记
|
||||||
// 重置核心业务标记
|
|
||||||
mCurrentConfigBean = null;
|
mCurrentConfigBean = null;
|
||||||
mForegroundNotifyMsg = null;
|
mForegroundNotifyMsg = null;
|
||||||
// 重置核心业务标记
|
|
||||||
mServiceHandler = null;
|
mServiceHandler = null;
|
||||||
isServiceRunning = false;
|
isServiceRunning = false;
|
||||||
mIsDestroyed = true;
|
mIsDestroyed = true;
|
||||||
LogUtils.d(TAG, "onDestroy: 服务销毁完成");
|
LogUtils.d(TAG, "===== onDestroy: 服务销毁流程完成 =====");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
|
LogUtils.d(TAG, "onBind: 服务绑定请求 | intent=" + intent);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 【核心抽取函数】运行服务核心逻辑 =================================
|
// ================================== 核心业务逻辑(抽取独立方法,统一管理)=================================
|
||||||
/**
|
/**
|
||||||
* 抽取的服务核心运行逻辑,统一在onCreate和onStartCommand调用
|
* 抽取的服务核心运行逻辑,统一在onCreate和onStartCommand调用
|
||||||
* 复用 isServiceRunning 做重复运行判断,避免重复初始化业务
|
* 复用 isServiceRunning 做重复运行判断,避免重复初始化业务
|
||||||
*/
|
*/
|
||||||
private void runCoreServiceLogic() {
|
private void runCoreServiceLogic() {
|
||||||
|
LogUtils.d(TAG, "runCoreServiceLogic: 开始执行核心业务逻辑");
|
||||||
loadLatestServiceControlConfig();
|
loadLatestServiceControlConfig();
|
||||||
|
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||||
|
LogUtils.d(TAG, "runCoreServiceLogic: 服务启用状态=" + serviceEnabled + " | 当前运行状态=" + isServiceRunning + " | 已销毁状态=" + mIsDestroyed);
|
||||||
|
|
||||||
// 核心校验:服务已启用 + 服务处于运行状态 + 未被销毁 + 业务未初始化(通过mServiceHandler判空)
|
// 核心校验:服务已启用 + 服务未运行 + 未被销毁
|
||||||
if (mServiceControlBean.isEnableService()) {
|
if (serviceEnabled) {
|
||||||
if (!isServiceRunning) {
|
if (!isServiceRunning && !mIsDestroyed) {
|
||||||
isServiceRunning = true;
|
isServiceRunning = true;
|
||||||
mIsDestroyed = false;
|
mIsDestroyed = false;
|
||||||
LogUtils.d(TAG, "runCoreServiceLogic: 开始执行服务核心业务");
|
LogUtils.d(TAG, "runCoreServiceLogic: 满足执行条件,开始初始化前台通知和业务组件");
|
||||||
// 初始化通知 + 默认配置 + Handler + 线程
|
|
||||||
// 优先发送前台通知,避免5秒超时异常
|
// 优先发送前台通知,避免5秒超时异常
|
||||||
initForegroundNotificationImmediately();
|
if (initForegroundNotificationImmediately()) {
|
||||||
// 加载本地服务控制配置
|
|
||||||
|
|
||||||
//initNotificationManager();
|
|
||||||
loadDefaultConfig();
|
loadDefaultConfig();
|
||||||
initServiceBusinessLogic();
|
initServiceBusinessLogic();
|
||||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务执行完成");
|
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务组件初始化完成");
|
||||||
} else {
|
} else {
|
||||||
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务已在运行,无需重复执行");
|
LogUtils.e(TAG, "runCoreServiceLogic: 前台通知初始化失败,终止核心业务执行");
|
||||||
|
stopForegroundService();
|
||||||
|
isServiceRunning = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LogUtils.d(TAG, "runCoreServiceLogic: 服务未启用,不执行核心业务");
|
LogUtils.d(TAG, "runCoreServiceLogic: 核心业务已运行或服务已销毁,无需重复执行");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogUtils.d(TAG, "runCoreServiceLogic: 服务未启用,跳过核心业务执行");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// ================================== 前台通知管理(优先执行,防止超时异常)=================================
|
||||||
|
|
||||||
// ================================== 前台通知核心方法(优先执行,防止超时)=================================
|
|
||||||
/**
|
/**
|
||||||
* 立即初始化前台通知,内置兜底方案
|
* 立即初始化前台通知,内置兜底方案
|
||||||
|
* @return true:通知初始化成功 false:通知初始化失败
|
||||||
*/
|
*/
|
||||||
private void initForegroundNotificationImmediately() {
|
private boolean initForegroundNotificationImmediately() {
|
||||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 初始化前台通知");
|
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程启动");
|
||||||
try {
|
try {
|
||||||
if (mNotificationManager == null) {
|
if (mNotificationManager == null) {
|
||||||
mNotificationManager = new NotificationManagerUtils(this);
|
mNotificationManager = new NotificationManagerUtils(this);
|
||||||
|
LogUtils.d(TAG, "initForegroundNotificationImmediately: 通知工具类初始化完成");
|
||||||
}
|
}
|
||||||
if (mForegroundNotifyMsg == null) {
|
if (mForegroundNotifyMsg == null) {
|
||||||
mForegroundNotifyMsg = new NotificationMessage();
|
mForegroundNotifyMsg = new NotificationMessage();
|
||||||
mForegroundNotifyMsg.setTitle("电池监测服务");
|
mForegroundNotifyMsg.setTitle("电池监测服务");
|
||||||
mForegroundNotifyMsg.setContent("后台运行中");
|
mForegroundNotifyMsg.setContent("后台运行中");
|
||||||
mForegroundNotifyMsg.setRemindMSG("service_running");
|
mForegroundNotifyMsg.setRemindMSG("service_running");
|
||||||
|
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知消息构建完成 | 标题=" + mForegroundNotifyMsg.getTitle() + " | 内容=" + mForegroundNotifyMsg.getContent());
|
||||||
}
|
}
|
||||||
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
|
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
|
||||||
ToastUtils.show("startForegroundServiceNotify 已调用");
|
ToastUtils.show("startForegroundServiceNotify 已调用");
|
||||||
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功,ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
|
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功 | 通知ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
|
||||||
|
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程成功结束");
|
||||||
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "initForegroundNotificationImmediately: 工具类发送失败,执行兜底方案", e);
|
LogUtils.e(TAG, "initForegroundNotificationImmediately: 前台通知初始化流程异常", e);
|
||||||
fallbackStartForeground();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前台通知兜底方案,直接构建Notification
|
* 停止前台服务并取消通知
|
||||||
*/
|
*/
|
||||||
private void fallbackStartForeground() {
|
private void stopForegroundService() {
|
||||||
|
LogUtils.d(TAG, "stopForegroundService: 停止前台服务流程启动");
|
||||||
try {
|
try {
|
||||||
Notification notification = new NotificationCompat.Builder(this, NotificationManagerUtils.CHANNEL_ID_FOREGROUND)
|
stopForeground(true);
|
||||||
.setContentTitle("电池监测服务")
|
LogUtils.d(TAG, "stopForegroundService: 前台服务停止成功,通知已取消");
|
||||||
.setContentText("后台运行中")
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
||||||
.build();
|
|
||||||
startForeground(NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE, notification);
|
|
||||||
LogUtils.d(TAG, "fallbackStartForeground: 兜底前台通知发送成功");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "fallbackStartForeground: 兜底发送失败,服务会被系统杀死", e);
|
LogUtils.e(TAG, "stopForegroundService: 停止前台服务异常", e);
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "stopForegroundService: 停止前台服务流程结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 服务控制配置管理(本地持久化+内存同步)=================================
|
// ================================== 配置管理(本地持久化+内存同步)=================================
|
||||||
/**
|
/**
|
||||||
* 读取本地最新服务控制配置
|
* 读取本地最新服务控制配置
|
||||||
*/
|
*/
|
||||||
private void loadLatestServiceControlConfig() {
|
private void loadLatestServiceControlConfig() {
|
||||||
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取本地配置");
|
LogUtils.d(TAG, "loadLatestServiceControlConfig: 读取本地服务控制配置");
|
||||||
ControlCenterServiceBean latestBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
|
ControlCenterServiceBean latestBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
|
||||||
if (latestBean != null) {
|
if (latestBean != null) {
|
||||||
mServiceControlBean = latestBean;
|
mServiceControlBean = latestBean;
|
||||||
LogUtils.d(TAG, "loadLatestServiceControlConfig: 配置更新完成,启用状态=" + mServiceControlBean.isEnableService());
|
LogUtils.d(TAG, "loadLatestServiceControlConfig: 本地配置读取成功 | 启用状态=" + mServiceControlBean.isEnableService());
|
||||||
} else {
|
} else {
|
||||||
LogUtils.w(TAG, "loadLatestServiceControlConfig: 本地无配置,沿用当前状态");
|
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() {
|
private void loadDefaultConfig() {
|
||||||
LogUtils.d(TAG, "loadDefaultConfig: 加载默认配置");
|
LogUtils.d(TAG, "loadDefaultConfig: 加载默认业务配置");
|
||||||
if (mCurrentConfigBean == null) {
|
if (mCurrentConfigBean == null) {
|
||||||
mCurrentConfigBean = new AppConfigBean();
|
mCurrentConfigBean = new AppConfigBean();
|
||||||
mCurrentConfigBean.setEnableChargeReminder(true);
|
mCurrentConfigBean.setEnableChargeReminder(true);
|
||||||
@@ -230,242 +208,214 @@ public class ControlCenterService extends Service {
|
|||||||
mCurrentConfigBean.setEnableUsageReminder(true);
|
mCurrentConfigBean.setEnableUsageReminder(true);
|
||||||
mCurrentConfigBean.setUsageReminderValue(20);
|
mCurrentConfigBean.setUsageReminderValue(20);
|
||||||
mCurrentConfigBean.setBatteryDetectInterval(1000);
|
mCurrentConfigBean.setBatteryDetectInterval(1000);
|
||||||
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成");
|
LogUtils.d(TAG, "loadDefaultConfig: 默认配置加载完成 | 充电阈值=" + 80 + " | 耗电阈值=" + 20 + " | 检测间隔=" + 1000 + "ms");
|
||||||
|
} else {
|
||||||
|
LogUtils.d(TAG, "loadDefaultConfig: 内存中已有业务配置,无需加载默认值 | 当前充电阈值=" + mCurrentConfigBean.getChargeReminderValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================== 业务组件初始化与销毁=================================
|
||||||
/**
|
/**
|
||||||
* 初始化业务核心逻辑(Handler+线程)
|
* 初始化业务核心逻辑(Handler+线程)
|
||||||
*/
|
*/
|
||||||
private void initServiceBusinessLogic() {
|
private void initServiceBusinessLogic() {
|
||||||
LogUtils.d(TAG, "initServiceBusinessLogic: 初始化Handler与线程");
|
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程启动");
|
||||||
if (mServiceHandler == null) {
|
if (mServiceHandler == null) {
|
||||||
mServiceHandler = new ControlCenterServiceHandler(this);
|
mServiceHandler = new ControlCenterServiceHandler(this);
|
||||||
|
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler初始化完成");
|
||||||
|
} else {
|
||||||
|
LogUtils.d(TAG, "initServiceBusinessLogic: ControlCenterServiceHandler已存在,无需重复初始化");
|
||||||
}
|
}
|
||||||
restartRemindThreadSafely();
|
restartRemindThreadSafely();
|
||||||
}
|
LogUtils.d(TAG, "initServiceBusinessLogic: 业务组件初始化流程结束");
|
||||||
|
|
||||||
// ================================== 提醒线程管理(安全启停,并发保护)=================================
|
|
||||||
/**
|
|
||||||
* 安全重启提醒线程
|
|
||||||
*/
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 安全停止提醒线程
|
* 销毁Handler,移除所有消息和回调
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
*/
|
||||||
private void destroyHandler() {
|
private void destroyHandler() {
|
||||||
LogUtils.d(TAG, "destroyHandler: 销毁Handler");
|
LogUtils.d(TAG, "destroyHandler: Handler销毁流程启动");
|
||||||
if (mServiceHandler != null) {
|
if (mServiceHandler != null) {
|
||||||
mServiceHandler.removeCallbacksAndMessages(null);
|
mServiceHandler.removeCallbacksAndMessages(null);
|
||||||
mServiceHandler = null;
|
mServiceHandler = null;
|
||||||
|
LogUtils.d(TAG, "destroyHandler: Handler已销毁,所有消息已移除");
|
||||||
|
} else {
|
||||||
|
LogUtils.w(TAG, "destroyHandler: Handler实例为空,无需销毁");
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "destroyHandler: Handler销毁流程结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 释放通知资源
|
* 释放通知资源
|
||||||
*/
|
*/
|
||||||
private void releaseNotificationResource() {
|
private void releaseNotificationResource() {
|
||||||
LogUtils.d(TAG, "releaseNotificationResource: 释放通知资源");
|
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放流程启动");
|
||||||
if (mNotificationManager != null) {
|
if (mNotificationManager != null) {
|
||||||
mNotificationManager.release();
|
mNotificationManager.release();
|
||||||
mNotificationManager = null;
|
mNotificationManager = null;
|
||||||
|
LogUtils.d(TAG, "releaseNotificationResource: 通知工具类资源释放完成");
|
||||||
|
} else {
|
||||||
|
LogUtils.w(TAG, "releaseNotificationResource: 通知工具类实例为空,无需释放");
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "releaseNotificationResource: 通知资源释放流程结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 置空所有引用
|
* 置空所有引用,防止内存泄漏
|
||||||
*/
|
*/
|
||||||
private void clearAllReferences() {
|
private void clearAllReferences() {
|
||||||
|
LogUtils.d(TAG, "clearAllReferences: 内存引用清理流程启动");
|
||||||
mForegroundNotifyMsg = null;
|
mForegroundNotifyMsg = null;
|
||||||
mCurrentConfigBean = null;
|
mCurrentConfigBean = null;
|
||||||
mServiceControlBean = 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) {
|
public static void startControlCenterService(Context context) {
|
||||||
LogUtils.d(TAG, "startControlCenterService: 启动服务");
|
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用 =====");
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
LogUtils.e(TAG, "startControlCenterService: Context为空");
|
LogUtils.e(TAG, "startControlCenterService: Context为空,启动失败");
|
||||||
return;
|
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);
|
Intent intent = new Intent(context, ControlCenterService.class);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
LogUtils.d(TAG, "startControlCenterService: SDK版本>=26,调用startForegroundService启动前台服务");
|
||||||
context.startForegroundService(intent);
|
context.startForegroundService(intent);
|
||||||
LogUtils.d(TAG, "startForegroundService 已调用");
|
|
||||||
} else {
|
} else {
|
||||||
|
LogUtils.d(TAG, "startControlCenterService: SDK版本<26,调用startService启动普通服务");
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
LogUtils.d(TAG, "startService 已调用");
|
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "===== startControlCenterService: 外部启动服务接口调用完成 =====");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止服务
|
* 停止服务
|
||||||
*/
|
*/
|
||||||
public static void stopControlCenterService(Context context) {
|
public static void stopControlCenterService(Context context) {
|
||||||
LogUtils.d(TAG, "stopControlCenterService: 停止服务");
|
LogUtils.d(TAG, "===== stopControlCenterService: 外部停止服务接口调用 =====");
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
LogUtils.e(TAG, "stopControlCenterService: Context为空");
|
LogUtils.e(TAG, "stopControlCenterService: Context为空,停止失败");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 保存服务停止配置
|
||||||
// 保存服务启动配置
|
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(false);
|
||||||
ControlCenterServiceBean.saveBean(context, new ControlCenterServiceBean(false));
|
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||||
|
LogUtils.d(TAG, "stopControlCenterService: 服务停止配置已保存 | 启用状态=" + controlBean.isEnableService());
|
||||||
|
// 构建停止Intent
|
||||||
Intent intent = new Intent(context, ControlCenterService.class);
|
Intent intent = new Intent(context, ControlCenterService.class);
|
||||||
|
LogUtils.d(TAG, "stopControlCenterService: 调用stopService发送停止指令");
|
||||||
context.stopService(intent);
|
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) {
|
public static void updateStatus(Context context, AppConfigBean configBean) {
|
||||||
LogUtils.d(TAG, "updateStatus: 发送配置更新指令");
|
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用 =====");
|
||||||
if (context == null || configBean == null) {
|
if (context == null || configBean == null) {
|
||||||
LogUtils.e(TAG, "updateStatus: 参数为空");
|
LogUtils.e(TAG, "updateStatus: 参数为空 | context=" + context + " | configBean=" + configBean);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "updateStatus: 待同步配置 | 充电阈值=" + configBean.getChargeReminderValue() + " | 耗电阈值=" + configBean.getUsageReminderValue());
|
||||||
|
// 构建配置更新Intent
|
||||||
Intent intent = new Intent(context, ControlCenterService.class);
|
Intent intent = new Intent(context, ControlCenterService.class);
|
||||||
intent.setAction(ACTION_RESTART_REMIND_THREAD);
|
intent.setAction(ACTION_RESTART_REMIND_THREAD);
|
||||||
intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
|
intent.putExtra(EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
|
||||||
@@ -473,21 +423,26 @@ public class ControlCenterService extends Service {
|
|||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
LogUtils.d(TAG, "updateStatus: SDK版本>=26,调用startForegroundService发送配置更新指令");
|
||||||
context.startForegroundService(intent);
|
context.startForegroundService(intent);
|
||||||
} else {
|
} else {
|
||||||
|
LogUtils.d(TAG, "updateStatus: SDK版本<26,调用startService发送配置更新指令");
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "updateStatus: 配置更新指令发送成功");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "updateStatus: 发送指令异常", e);
|
LogUtils.e(TAG, "updateStatus: 发送配置更新指令异常", e);
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "===== updateStatus: 外部更新配置接口调用完成 =====");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查并引导用户开启忽略电池优化
|
* 检查并引导用户开启忽略电池优化
|
||||||
*/
|
*/
|
||||||
public static void checkIgnoreBatteryOptimization(Context context) {
|
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) {
|
if (context == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
LogUtils.w(TAG, "checkIgnoreBatteryOptimization: 无需检查 | context=" + context + " | SDK版本=" + (Build.VERSION.SDK_INT));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
@@ -496,32 +451,43 @@ public class ControlCenterService extends Service {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
|
String packageName = context.getPackageName();
|
||||||
|
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||||
|
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 当前忽略电池优化状态=" + isIgnored);
|
||||||
if (!isIgnored) {
|
if (!isIgnored) {
|
||||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
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);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化");
|
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已跳转至系统设置页,引导用户开启忽略电池优化");
|
||||||
|
} else {
|
||||||
|
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已开启忽略电池优化,无需引导");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导异常", e);
|
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导用户开启忽略电池优化异常", e);
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 电池优化检查流程结束");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断服务是否运行(适配API30+)
|
* 判断服务是否运行(适配API30+)
|
||||||
*/
|
*/
|
||||||
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
||||||
|
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程启动 | serviceClass=" + (serviceClass != null ? serviceClass.getName() : "null"));
|
||||||
if (context == null || serviceClass == null) {
|
if (context == null || serviceClass == null) {
|
||||||
|
LogUtils.e(TAG, "isServiceRunning: 参数为空 | context=" + context + " | serviceClass=" + serviceClass);
|
||||||
|
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
if (am == null) {
|
if (am == null) {
|
||||||
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败");
|
LogUtils.e(TAG, "isServiceRunning: ActivityManager获取失败");
|
||||||
|
LogUtils.d(TAG, "isServiceRunning: 服务运行状态检查流程结束 | 结果=false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
boolean isRunning = false;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
LogUtils.d(TAG, "isServiceRunning: SDK版本>=30,使用进程信息判断");
|
||||||
String packageName = context.getPackageName();
|
String packageName = context.getPackageName();
|
||||||
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
|
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
|
||||||
if (processes != null) {
|
if (processes != null) {
|
||||||
@@ -529,60 +495,68 @@ public class ControlCenterService extends Service {
|
|||||||
if (packageName.equals(process.processName) &&
|
if (packageName.equals(process.processName) &&
|
||||||
(process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE ||
|
(process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE ||
|
||||||
process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)) {
|
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 {
|
} else {
|
||||||
|
LogUtils.d(TAG, "isServiceRunning: SDK版本<30,使用服务列表判断");
|
||||||
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);
|
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(100);
|
||||||
if (runningServices != null) {
|
if (runningServices != null) {
|
||||||
String serviceClassName = serviceClass.getName();
|
String serviceClassName = serviceClass.getName();
|
||||||
for (ActivityManager.RunningServiceInfo info : runningServices) {
|
for (ActivityManager.RunningServiceInfo info : runningServices) {
|
||||||
if (serviceClassName.equals(info.service.getClassName())) {
|
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) {
|
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
|
||||||
|
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程启动");
|
||||||
|
boolean result = false;
|
||||||
try {
|
try {
|
||||||
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
|
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) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "isServiceStarted: 兜底判断异常", e);
|
LogUtils.e(TAG, "isServiceStarted: 兜底判断异常", e);
|
||||||
return false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "isServiceStarted: 服务状态兜底判断流程结束 | 结果=" + result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== Getter/Setter 方法(线程安全)=================================
|
// ================================== Getter/Setter 方法(添加日志)=================================
|
||||||
public RemindThread getRemindThread() {
|
public RemindThread getRemindThread() {
|
||||||
return mRemindThread;
|
return mRemindThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentConfigBean(AppConfigBean configBean) {
|
public void setCurrentConfigBean(AppConfigBean configBean) {
|
||||||
LogUtils.d(TAG, "setCurrentConfigBean: 更新业务配置");
|
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新接口调用");
|
||||||
if (configBean == null) {
|
if (configBean == null) {
|
||||||
LogUtils.e(TAG, "setCurrentConfigBean: 配置为空");
|
LogUtils.e(TAG, "setCurrentConfigBean: 待更新配置为空,更新失败");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.mCurrentConfigBean = configBean;
|
this.mCurrentConfigBean = configBean;
|
||||||
syncConfigToRemindThread();
|
syncConfigToRemindThread();
|
||||||
|
LogUtils.d(TAG, "setCurrentConfigBean: 业务配置更新完成 | 新充电阈值=" + configBean.getChargeReminderValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setServiceControlBean(ControlCenterServiceBean controlBean) {
|
|
||||||
// LogUtils.d(TAG, "setServiceControlBean: 更新控制配置");
|
|
||||||
// if (controlBean != null) {
|
|
||||||
// updateAndSaveServiceControlConfig(controlBean);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public ControlCenterServiceBean getServiceControlBean() {
|
public ControlCenterServiceBean getServiceControlBean() {
|
||||||
return mServiceControlBean;
|
return mServiceControlBean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,79 +8,137 @@ import cc.winboll.studio.powerbell.models.AppConfigBean;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
* 提醒线程(单例模式)
|
||||||
* @Date 2025/12/17 13:38
|
* 功能:统一管理充电/耗电提醒逻辑,发送提醒时携带当前电量+充电状态
|
||||||
* @Describe 提醒线程(单例模式):统一管理充电/耗电提醒逻辑,适配Java7+API30+,发送提醒时同步携带当前电量+充电状态
|
* 适配:Java7 | API30 | 小米手机
|
||||||
|
* 特性:线程安全、内存泄漏防护、配置重试兜底
|
||||||
|
* 对外接口:仅保留 {@link #startRemindThread(Context, ControlCenterServiceHandler, AppConfigBean)} 和 {@link #stopRemindThread()}
|
||||||
*/
|
*/
|
||||||
public class RemindThread extends Thread {
|
public class RemindThread extends Thread {
|
||||||
// ================================== 静态常量(置顶,统一管理魔法值)=================================
|
// ================================== 静态常量(置顶归类,消除魔法值)=================================
|
||||||
public static final String TAG = "RemindThread";
|
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;
|
private static volatile RemindThread sInstance;
|
||||||
|
|
||||||
// ================================== 成员变量(按功能分类,volatile+锁保护)=================================
|
// ================================== 成员变量(按功能分层,volatile保证多线程可见性,防内存泄漏)=================================
|
||||||
// 依赖资源(防内存泄漏)
|
// 弱引用依赖(避免内存泄漏)
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
|
private WeakReference<ControlCenterServiceHandler> mwrControlCenterServiceHandler;
|
||||||
|
|
||||||
// 线程状态(核心标记,多线程可见)
|
// 线程状态标记(volatile 保证多线程可见性)
|
||||||
private volatile boolean isExist; // 退出标记(true=退出)
|
private volatile boolean isExist;
|
||||||
private volatile boolean isThreadStarted; // 启动标记(区分isAlive())
|
private volatile boolean isThreadStarted;
|
||||||
private volatile boolean isReminding; // 全局提醒开关
|
private volatile boolean isReminding;
|
||||||
private volatile boolean isRemindTimerRunning; // 提醒恢复计时器状态
|
private volatile boolean isRemindTimerRunning;
|
||||||
|
|
||||||
// 业务配置(实时同步,范围校验)
|
// 业务配置参数(范围校验,实时同步)
|
||||||
private volatile boolean isEnableChargeReminder; // 充电提醒开关
|
private volatile boolean isEnableChargeReminder;
|
||||||
private volatile boolean isEnableUsageReminder; // 耗电提醒开关
|
private volatile boolean isEnableUsageReminder;
|
||||||
private volatile long sleepTime; // 检测间隔(ms,改为long适配大间隔)
|
private volatile long sleepTime;
|
||||||
private volatile int chargeReminderValue; // 充电提醒阈值(0-100)
|
private volatile int chargeReminderValue;
|
||||||
private volatile int usageReminderValue; // 耗电提醒阈值(0-100)
|
private volatile int usageReminderValue;
|
||||||
private volatile int quantityOfElectricity; // 当前电量(0-100,无效为-1)
|
private volatile int quantityOfElectricity;
|
||||||
private volatile boolean isCharging; // 充电状态标记
|
private volatile boolean isCharging;
|
||||||
|
|
||||||
// 辅助变量(并发安全+防重复提醒)
|
// 辅助变量(并发安全+防重复提醒)
|
||||||
private volatile long lastRemindTime; // 上次提醒时间戳(ms)
|
private volatile long lastRemindTime;
|
||||||
private final Object mLock = new Object(); // 全局锁(保护所有状态变量)
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
// ================================== 私有构造器(单例专用,初始化状态+防护泄漏)=================================
|
// ================================== 私有构造器(单例专用,初始化状态+防护泄漏)=================================
|
||||||
private RemindThread(Context context, ControlCenterServiceHandler handler) {
|
private RemindThread(Context context, ControlCenterServiceHandler handler) {
|
||||||
LogUtils.d(TAG, "构造线程实例,线程名称:" + getName());
|
|
||||||
this.mContext = context.getApplicationContext();
|
this.mContext = context.getApplicationContext();
|
||||||
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
|
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) {
|
public static boolean startRemindThread(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
|
||||||
LogUtils.d(TAG, "获取单例,当前实例是否存在:" + (sInstance != null));
|
// 入参校验
|
||||||
if (context == null || handler == null) {
|
if (context == null || handler == null || config == null) {
|
||||||
LogUtils.e(TAG, "致命错误:Context/ControlCenterServiceHandler不能为空");
|
LogUtils.e(TAG, "startRemindThread: 入参为空,启动失败");
|
||||||
throw new IllegalArgumentException("Context and ControlCenterServiceHandler cannot be null");
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 旧线程停止则销毁,确保新实例有效
|
// 1. 若 isReminding 为真,直接返回 true 无需操作
|
||||||
if (sInstance != null && !sInstance.isRunning()) {
|
if (sInstance != null && sInstance.isReminding) {
|
||||||
destroyInstance();
|
LogUtils.d(TAG, "startRemindThread: isReminding为true,直接返回");
|
||||||
LogUtils.d(TAG, "旧线程已停止,销毁单例准备创建新实例");
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 双重校验锁创建单例
|
// 2. 未创建实例则创建
|
||||||
if (sInstance == null) {
|
if (sInstance == null) {
|
||||||
synchronized (RemindThread.class) {
|
synchronized (RemindThread.class) {
|
||||||
if (sInstance == null) {
|
if (sInstance == null) {
|
||||||
sInstance = new RemindThread(context, handler);
|
sInstance = new RemindThread(context, handler);
|
||||||
LogUtils.d(TAG, "新线程实例创建成功,线程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() {
|
private static void destroyInstance() {
|
||||||
LogUtils.d(TAG, "开始销毁线程单例");
|
LogUtils.d(TAG, "destroyInstance: 开始销毁线程单例");
|
||||||
synchronized (RemindThread.class) {
|
synchronized (RemindThread.class) {
|
||||||
if (sInstance != null) {
|
if (sInstance != null) {
|
||||||
sInstance.stopThread();
|
sInstance.isExist = true;
|
||||||
sInstance.releaseResources();
|
sInstance.isReminding = false;
|
||||||
|
sInstance.isRemindTimerRunning = false;
|
||||||
|
if (sInstance.isAlive()) {
|
||||||
|
sInstance.interrupt();
|
||||||
|
LogUtils.d(TAG, "destroyInstance: 线程已中断");
|
||||||
|
}
|
||||||
|
sInstance.releaseResourcesInternal();
|
||||||
sInstance = null;
|
sInstance = null;
|
||||||
LogUtils.d(TAG, "线程单例销毁完成");
|
LogUtils.d(TAG, "destroyInstance: 线程单例销毁完成");
|
||||||
} else {
|
} else {
|
||||||
LogUtils.w(TAG, "单例已为空,跳过销毁");
|
LogUtils.w(TAG, "destroyInstance: 单例已为空,跳过销毁");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 线程核心逻辑(run方法,高效退出+异常容错)=================================
|
// ================================== 线程核心逻辑(run方法,高效退出+异常容错,仅此处保留mLock)=================================
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LogUtils.d(TAG, "线程启动,ID:" + Thread.currentThread().getId() + ",状态:" + getState());
|
LogUtils.d(TAG, "run: 线程启动 | threadId=" + Thread.currentThread().getId() + " | state=" + getState());
|
||||||
// 防止run方法重复执行
|
|
||||||
|
// 仅保留此处的mLock,保护isReminding等核心状态的读写,防止线程重复启动
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (isThreadStarted || isExist) {
|
if (isThreadStarted || isExist) {
|
||||||
LogUtils.e(TAG, "线程已启动/待退出,禁止重复执行run");
|
LogUtils.e(TAG, "run: 线程重复启动 | isThreadStarted=" + isThreadStarted + " | isExist=" + isExist);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isThreadStarted = true;
|
isThreadStarted = true;
|
||||||
lastRemindTime = 0;
|
lastRemindTime = 0;
|
||||||
|
// 确保isReminding初始状态正确
|
||||||
|
isReminding = isEnableChargeReminder || isEnableUsageReminder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置同步重试(失败则兜底默认值)
|
// 配置同步重试(失败则兜底默认值)
|
||||||
boolean configValid = syncConfigRetry();
|
boolean configValid = syncConfigRetry();
|
||||||
if (!configValid) {
|
if (!configValid) {
|
||||||
LogUtils.e(TAG, "配置同步失败,使用默认阈值兜底启动");
|
LogUtils.e(TAG, "run: 配置同步失败,使用兜底阈值启动");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化延迟(等待服务就绪)
|
// 初始化延迟(等待服务就绪)
|
||||||
try {
|
try {
|
||||||
LogUtils.d(TAG, "初始化延迟" + INIT_DELAY_TIME + "ms");
|
LogUtils.d(TAG, "run: 初始化延迟 | delayTime=" + INIT_DELAY_TIME + "ms");
|
||||||
Thread.sleep(INIT_DELAY_TIME);
|
Thread.sleep(INIT_DELAY_TIME);
|
||||||
if (isExist) {
|
if (isExist) {
|
||||||
LogUtils.d(TAG, "延迟期间收到退出指令,线程终止");
|
LogUtils.d(TAG, "run: 延迟期间收到退出指令,线程终止");
|
||||||
cleanThreadState();
|
cleanThreadStateInternal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
LogUtils.e(TAG, "初始化延迟被中断,线程终止", e);
|
LogUtils.e(TAG, "run: 初始化延迟被中断,线程终止", e);
|
||||||
cleanThreadState();
|
cleanThreadStateInternal();
|
||||||
return;
|
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) {
|
while (!isExist) {
|
||||||
try {
|
try {
|
||||||
if (isExist) break;
|
if (isExist) break;
|
||||||
|
|
||||||
// 核心防护:提醒关闭/电量无效,直接休眠(跳过提醒检测)
|
// 核心防护:提醒关闭/电量无效,直接休眠(依赖volatile保证可见性)
|
||||||
synchronized (mLock) {
|
|
||||||
// 提醒关闭/电量无效:正常休眠,不检测
|
|
||||||
if (!isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
|
if (!isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
|
||||||
safeSleep(sleepTime);
|
safeSleepInternal(sleepTime);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 电量超出范围:修正为无效,休眠重试
|
// 电量超出范围:修正为无效值
|
||||||
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
||||||
LogUtils.w(TAG, "电量无效(" + quantityOfElectricity + "),标记为无效值");
|
LogUtils.w(TAG, "run: 电量无效,修正为无效值 | currentBattery=" + quantityOfElectricity);
|
||||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||||
safeSleep(sleepTime);
|
safeSleepInternal(sleepTime);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 锁保护核心提醒逻辑(仅提醒开启+电量有效时执行)
|
|
||||||
synchronized (mLock) {
|
|
||||||
if (isExist || !isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
|
|
||||||
safeSleep(sleepTime);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 防重复提醒(间隔未到/计时器运行中)
|
// 防重复提醒(间隔未到/计时器运行中,依赖volatile保证可见性)
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
if ((currentTime - lastRemindTime < REMIND_INTERVAL) || isRemindTimerRunning) {
|
if ((currentTime - lastRemindTime < REMIND_INTERVAL) || isRemindTimerRunning) {
|
||||||
safeSleep(sleepTime);
|
safeSleepInternal(sleepTime);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 充电提醒触发(携带当前电量+充电状态发送)
|
// 充电提醒触发
|
||||||
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
|
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
|
||||||
LogUtils.d(TAG, "触发充电提醒:充电中,电量" + quantityOfElectricity + "≥阈值" + chargeReminderValue);
|
LogUtils.d(TAG, "run: 循环检测触发充电提醒 | battery=" + quantityOfElectricity + " ≥ threshold=" + chargeReminderValue);
|
||||||
sendNotificationMessage("+", quantityOfElectricity, isCharging);
|
sendNotificationMessageInternal("+", quantityOfElectricity, isCharging);
|
||||||
lastRemindTime = currentTime;
|
lastRemindTime = currentTime;
|
||||||
startRemindRecoveryTimer();
|
startRemindRecoveryTimerInternal();
|
||||||
}
|
}
|
||||||
// 耗电提醒触发(携带当前电量+充电状态发送)
|
// 耗电提醒触发
|
||||||
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
|
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
|
||||||
LogUtils.d(TAG, "触发耗电提醒:未充电,电量" + quantityOfElectricity + "≤阈值" + usageReminderValue);
|
LogUtils.d(TAG, "run: 循环检测触发耗电提醒 | battery=" + quantityOfElectricity + " ≤ threshold=" + usageReminderValue);
|
||||||
sendNotificationMessage("-", quantityOfElectricity, isCharging);
|
sendNotificationMessageInternal("-", quantityOfElectricity, isCharging);
|
||||||
lastRemindTime = currentTime;
|
lastRemindTime = currentTime;
|
||||||
startRemindRecoveryTimer();
|
startRemindRecoveryTimerInternal();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
safeSleep(sleepTime);
|
safeSleepInternal(sleepTime);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "线程运行异常,休眠重试", e);
|
LogUtils.e(TAG, "run: 线程运行异常,休眠重试", e);
|
||||||
safeSleep(sleepTime);
|
safeSleepInternal(sleepTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退出清理
|
// 退出清理
|
||||||
cleanThreadState();
|
cleanThreadStateInternal();
|
||||||
LogUtils.d(TAG, "线程循环退出,ID:" + Thread.currentThread().getId());
|
LogUtils.d(TAG, "run: 线程循环退出 | threadId=" + Thread.currentThread().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 核心业务辅助方法(配置同步+消息发送+计时器)=================================
|
// ================================== 核心业务辅助方法(全部私有化,移除对外访问)=================================
|
||||||
/**
|
/**
|
||||||
* 配置同步重试(确保阈值有效,失败兜底)
|
* 配置同步重试(确保阈值有效,失败兜底)
|
||||||
*/
|
*/
|
||||||
private boolean syncConfigRetry() {
|
private boolean syncConfigRetry() {
|
||||||
|
LogUtils.d(TAG, "syncConfigRetry: 开始配置同步 | maxRetry=" + CONFIG_RETRY_MAX);
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
|
|
||||||
while (retryCount < CONFIG_RETRY_MAX) {
|
while (retryCount < CONFIG_RETRY_MAX) {
|
||||||
synchronized (mLock) {
|
boolean chargeValid = chargeReminderValue >= 0 && chargeReminderValue <= 100;
|
||||||
if ((chargeReminderValue >= 0 && chargeReminderValue <= 100)
|
boolean usageValid = usageReminderValue >= 0 && usageReminderValue <= 100;
|
||||||
&& (usageReminderValue >= 0 && usageReminderValue <= 100)) {
|
if (chargeValid && usageValid) {
|
||||||
LogUtils.d(TAG, "配置同步成功,重试次数:" + retryCount);
|
LogUtils.d(TAG, "syncConfigRetry: 配置同步成功 | retryCount=" + retryCount);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
LogUtils.w(TAG, "syncConfigRetry: 配置未同步,重试 | retryCount=" + (retryCount + 1));
|
||||||
LogUtils.w(TAG, "配置未同步,重试次数:" + (retryCount + 1));
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
retryCount++;
|
retryCount++;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
LogUtils.e(TAG, "配置重试被中断", e);
|
LogUtils.e(TAG, "syncConfigRetry: 配置重试被中断", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 兜底默认阈值(避免无效值触发提醒)
|
|
||||||
synchronized (mLock) {
|
// 兜底默认阈值
|
||||||
chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
|
chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
|
||||||
usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
|
usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
|
||||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 兜底电量设为无效,防止误触发
|
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||||
LogUtils.e(TAG, "配置重试失败,兜底阈值:充电" + chargeReminderValue + ",耗电" + usageReminderValue + "RuntimeException : Config sync failed.");
|
LogUtils.e(TAG, "syncConfigRetry: 配置重试失败,使用兜底阈值 | chargeThreshold=" + chargeReminderValue + " | usageThreshold=" + usageReminderValue);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送提醒消息(携带当前电量+充电状态,弱引用Handler+Message复用,防泄漏)
|
* 发送提醒消息(携带当前电量+充电状态,弱引用Handler+Message复用,防泄漏)
|
||||||
* @param type 提醒类型(+:充电提醒,-:耗电提醒)
|
|
||||||
* @param battery 当前电量(0-100)
|
|
||||||
* @param isCharging 当前充电状态(true=充电中)
|
|
||||||
*/
|
*/
|
||||||
private void sendNotificationMessage(String type, int battery, boolean isCharging) {
|
private void sendNotificationMessageInternal(String type, int battery, boolean isCharging) {
|
||||||
LogUtils.d(TAG, "准备发送提醒消息:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
|
LogUtils.d(TAG, "sendNotificationMessageInternal: 准备发送提醒 | type=" + type + " | battery=" + battery + " | isCharging=" + isCharging);
|
||||||
// 双重防护:线程退出/提醒关闭,跳过发送
|
|
||||||
if (isExist || !isReminding) {
|
if (isExist || !isReminding) {
|
||||||
LogUtils.d(TAG, "线程退出/提醒关闭,跳过发送");
|
LogUtils.d(TAG, "sendNotificationMessageInternal: 线程退出或提醒关闭,跳过发送");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler != null ? mwrControlCenterServiceHandler.get() : null;
|
ControlCenterServiceHandler handler = mwrControlCenterServiceHandler != null ? mwrControlCenterServiceHandler.get() : null;
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
LogUtils.w(TAG, "Handler已回收,发送失败");
|
LogUtils.w(TAG, "sendNotificationMessageInternal: Handler已回收,发送失败");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建消息:what=提醒标识,obj=类型,arg1=当前电量,arg2=充电状态(0=未充电,1=充电中)
|
|
||||||
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT);
|
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT);
|
||||||
message.obj = type;
|
message.obj = type;
|
||||||
message.arg1 = battery;
|
message.arg1 = battery;
|
||||||
message.arg2 = isCharging ? 1 : 0; // boolean转int(兼容Java7)
|
message.arg2 = isCharging ? 1 : 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
handler.sendMessage(message);
|
handler.sendMessage(message);
|
||||||
LogUtils.d(TAG, "提醒消息发送成功:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
|
LogUtils.d(TAG, "sendNotificationMessageInternal: 提醒消息发送成功");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "消息发送异常", e);
|
LogUtils.e(TAG, "sendNotificationMessageInternal: 消息发送异常", e);
|
||||||
if (message != null) message.recycle();
|
if (message != null) message.recycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动提醒恢复计时器(防重复提醒,弱引用线程+锁保护)
|
* 启动提醒恢复计时器(防重复提醒,弱引用线程)
|
||||||
*/
|
*/
|
||||||
private void startRemindRecoveryTimer() {
|
private void startRemindRecoveryTimerInternal() {
|
||||||
LogUtils.d(TAG, "启动提醒恢复计时器,间隔:" + REMIND_INTERVAL + "ms");
|
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 启动提醒恢复计时器 | interval=" + REMIND_INTERVAL + "ms");
|
||||||
synchronized (mLock) {
|
|
||||||
if (isExist || isRemindTimerRunning || sInstance != this) {
|
if (isExist || isRemindTimerRunning || sInstance != this) {
|
||||||
LogUtils.w(TAG, "计时器启动条件不满足,跳过");
|
LogUtils.w(TAG, "startRemindRecoveryTimerInternal: 计时器启动条件不满足");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isReminding = false;
|
isReminding = false;
|
||||||
isRemindTimerRunning = true;
|
isRemindTimerRunning = true;
|
||||||
}
|
|
||||||
|
|
||||||
final WeakReference<RemindThread> threadRef = new WeakReference<>(this);
|
final WeakReference<RemindThread> threadRef = new WeakReference<>(this);
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@@ -293,323 +363,136 @@ public class RemindThread extends Thread {
|
|||||||
try {
|
try {
|
||||||
Thread.sleep(REMIND_INTERVAL);
|
Thread.sleep(REMIND_INTERVAL);
|
||||||
RemindThread thread = threadRef.get();
|
RemindThread thread = threadRef.get();
|
||||||
|
|
||||||
if (thread == null || thread.isExist || sInstance != thread) {
|
if (thread == null || thread.isExist || sInstance != thread) {
|
||||||
LogUtils.d(TAG, "线程已销毁,不恢复提醒");
|
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 线程已销毁,不恢复提醒");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (thread.mLock) {
|
boolean canRecover = !thread.isExist && sInstance == thread && (thread.isEnableChargeReminder || thread.isEnableUsageReminder);
|
||||||
// 仅线程存活+有启用提醒时,才恢复提醒
|
if (canRecover) {
|
||||||
if (!thread.isExist && sInstance == thread
|
|
||||||
&& (thread.isEnableChargeReminder || thread.isEnableUsageReminder)) {
|
|
||||||
thread.isReminding = true;
|
thread.isReminding = true;
|
||||||
LogUtils.d(TAG, "提醒功能恢复开启");
|
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒功能恢复开启");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
LogUtils.e(TAG, "计时器被中断", e);
|
LogUtils.e(TAG, "startRemindRecoveryTimerInternal: 计时器被中断", e);
|
||||||
} finally {
|
} finally {
|
||||||
RemindThread thread = threadRef.get();
|
RemindThread thread = threadRef.get();
|
||||||
if (thread != null) {
|
if (thread != null && sInstance == thread) {
|
||||||
synchronized (thread.mLock) {
|
thread.isRemindTimerRunning = false;
|
||||||
if (sInstance == thread) thread.isRemindTimerRunning = false;
|
|
||||||
}
|
}
|
||||||
}
|
LogUtils.d(TAG, "startRemindRecoveryTimerInternal: 提醒恢复计时器执行完成");
|
||||||
LogUtils.d(TAG, "提醒恢复计时器执行完成");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "RemindRecoveryTimer").start();
|
}, "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 {
|
try {
|
||||||
Thread.sleep(millis);
|
Thread.sleep(millis);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
LogUtils.w(TAG, "休眠被中断,线程准备退出");
|
LogUtils.w(TAG, "safeSleepInternal: 休眠被中断,线程准备退出");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清理线程运行状态(退出后重置所有标记)
|
* 清理线程运行状态(退出后重置所有标记)
|
||||||
*/
|
*/
|
||||||
private void cleanThreadState() {
|
private void cleanThreadStateInternal() {
|
||||||
LogUtils.d(TAG, "清理线程运行状态");
|
LogUtils.d(TAG, "cleanThreadStateInternal: 清理线程运行状态");
|
||||||
synchronized (mLock) {
|
|
||||||
isReminding = false;
|
isReminding = false;
|
||||||
isExist = true;
|
isExist = true;
|
||||||
isThreadStarted = false;
|
isThreadStarted = false;
|
||||||
isRemindTimerRunning = false;
|
isRemindTimerRunning = false;
|
||||||
lastRemindTime = 0;
|
lastRemindTime = 0;
|
||||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 重置为无效电量,防残留
|
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||||
}
|
|
||||||
if (isAlive()) interrupt();
|
if (isAlive()) interrupt();
|
||||||
if (sInstance == this) sInstance = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 状态重置方法(初始化+运行时重置)=================================
|
|
||||||
/**
|
/**
|
||||||
* 初始状态重置(构造器专用)
|
* 初始状态重置(构造器专用)
|
||||||
*/
|
*/
|
||||||
private void resetThreadStateInternal() {
|
private void resetThreadStateInternal() {
|
||||||
LogUtils.d(TAG, "重置线程初始状态");
|
LogUtils.d(TAG, "resetThreadStateInternal: 重置线程初始状态");
|
||||||
synchronized (mLock) {
|
|
||||||
// 线程状态
|
|
||||||
isExist = false;
|
isExist = false;
|
||||||
isReminding = false;
|
isReminding = false;
|
||||||
isThreadStarted = false;
|
isThreadStarted = false;
|
||||||
isRemindTimerRunning = false;
|
isRemindTimerRunning = false;
|
||||||
lastRemindTime = 0;
|
lastRemindTime = 0;
|
||||||
// 业务配置
|
|
||||||
isEnableChargeReminder = false;
|
isEnableChargeReminder = false;
|
||||||
isEnableUsageReminder = false;
|
isEnableUsageReminder = false;
|
||||||
sleepTime = DEFAULT_SLEEP_TIME;
|
sleepTime = DEFAULT_SLEEP_TIME;
|
||||||
chargeReminderValue = -1;
|
chargeReminderValue = -1;
|
||||||
usageReminderValue = -1;
|
usageReminderValue = -1;
|
||||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 初始设为无效
|
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||||
isCharging = false;
|
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) {
|
public void setAppConfigBean(AppConfigBean config) {
|
||||||
|
LogUtils.d(TAG, "setAppConfigBean: 开始同步应用配置 | config=" + config);
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
LogUtils.e(TAG, "配置Bean为空,同步失败");
|
LogUtils.e(TAG, "setAppConfigBean: 配置Bean为空,同步失败");
|
||||||
synchronized (mLock) {
|
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 配置为空,标记电量无效
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LogUtils.d(TAG, "开始同步配置:充电阈值" + config.getChargeReminderValue() + ",耗电阈值" + config.getUsageReminderValue() + ",当前电量" + config.getCurrentBatteryValue());
|
|
||||||
synchronized (mLock) {
|
|
||||||
// 同步开关
|
|
||||||
isEnableChargeReminder = config.isEnableChargeReminder();
|
isEnableChargeReminder = config.isEnableChargeReminder();
|
||||||
isEnableUsageReminder = config.isEnableUsageReminder();
|
isEnableUsageReminder = config.isEnableUsageReminder();
|
||||||
// 同步阈值(0-100限制)
|
|
||||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
|
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
|
||||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
|
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
|
||||||
// 同步检测间隔(≥最小间隔)
|
|
||||||
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
||||||
// 同步电池状态(校验有效,无效则标记为-1)
|
|
||||||
int currentBattery = config.getCurrentBatteryValue();
|
int currentBattery = config.getCurrentBatteryValue();
|
||||||
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
|
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
|
||||||
isCharging = config.isCharging();
|
isCharging = config.isCharging();
|
||||||
// 提醒开关:根据配置自动开启
|
isReminding = isEnableChargeReminder || isEnableUsageReminder;
|
||||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
|
||||||
}
|
LogUtils.d(TAG, "setAppConfigBean: 配置同步完成 | sleepTime=" + sleepTime + "ms | isReminding=" + isReminding + " | currentBattery=" + quantityOfElectricity);
|
||||||
LogUtils.d(TAG, "配置同步完成:检测间隔" + sleepTime + "ms,全局提醒" + isReminding + ",当前电量" + quantityOfElectricity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== Setter/Getter(锁保护,线程安全+精准日志)=================================
|
/**
|
||||||
public boolean isExist() {
|
* 判断线程是否处于运行状态
|
||||||
synchronized (mLock) {
|
*/
|
||||||
return isExist;
|
private boolean isRunning() {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsExist(boolean isExist) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
this.isExist = isExist;
|
|
||||||
LogUtils.d(TAG, "设置线程退出标记:" + isExist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
boolean running = !isExist && isThreadStarted && isAlive();
|
||||||
LogUtils.d(TAG, "线程运行状态:" + running + "(退出:" + isExist + ",已启动:" + isThreadStarted + ",存活:" + isAlive() + ")");
|
LogUtils.d(TAG, "isRunning: 线程运行状态=" + running + " | isExist=" + isExist + " | isThreadStarted=" + isThreadStarted + " | isAlive=" + isAlive());
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ================================== 资源释放(彻底断开引用,防内存泄漏)=================================
|
/**
|
||||||
public void releaseResources() {
|
* 释放线程所有资源(内部方法)
|
||||||
LogUtils.d(TAG, "开始释放线程资源");
|
*/
|
||||||
synchronized (mLock) {
|
private void releaseResourcesInternal() {
|
||||||
|
LogUtils.d(TAG, "releaseResourcesInternal: 开始释放线程资源");
|
||||||
mContext = null;
|
mContext = null;
|
||||||
if (mwrControlCenterServiceHandler != null) {
|
if (mwrControlCenterServiceHandler != null) {
|
||||||
mwrControlCenterServiceHandler.clear();
|
mwrControlCenterServiceHandler.clear();
|
||||||
mwrControlCenterServiceHandler = null;
|
mwrControlCenterServiceHandler = null;
|
||||||
}
|
}
|
||||||
cleanThreadState();
|
cleanThreadStateInternal();
|
||||||
}
|
LogUtils.d(TAG, "releaseResourcesInternal: 线程资源释放完成");
|
||||||
LogUtils.d(TAG, "线程资源释放完成");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 调试辅助(toString,打印核心状态)=================================
|
// ================================== 调试辅助(toString 私有化,避免对外暴露状态)=================================
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RemindThread{" +
|
return "RemindThread{" +
|
||||||
"threadId=" + getId() +
|
"threadId=" + getId() +
|
||||||
", threadName='" + getName() + '\'' +
|
", threadName='" + getName() + '\'' +
|
||||||
", isRunning=" + isRunning() +
|
", isRunning=" + isRunning() +
|
||||||
", isReminding=" + isReminding() +
|
", isReminding=" + isReminding +
|
||||||
", chargeThreshold=" + getChargeReminderValue() +
|
", chargeThreshold=" + chargeReminderValue +
|
||||||
", usageThreshold=" + getUsageReminderValue() +
|
", usageThreshold=" + usageReminderValue +
|
||||||
", currentBattery=" + getQuantityOfElectricity() +
|
", currentBattery=" + quantityOfElectricity +
|
||||||
", isCharging=" + isCharging() +
|
", isCharging=" + isCharging +
|
||||||
", sleepTime=" + getSleepTime() + "ms" +
|
", sleepTime=" + sleepTime + "ms" +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user