服务启停调试中。。。

This commit is contained in:
2025-12-17 20:40:04 +08:00
parent d61d1da5d1
commit 5e6de91430
4 changed files with 271 additions and 370 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Dec 17 08:49:06 GMT 2025 #Wed Dec 17 12:37:54 GMT 2025
stageCount=10 stageCount=10
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.9 publishVersion=15.14.9
buildCount=18 buildCount=25
baseBetaVersion=15.14.10 baseBetaVersion=15.14.10

View File

@@ -45,6 +45,7 @@ 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开关仅管理本地配置服务启停仅在应用启动时根据配置执行
*/ */
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener { public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)======================== // ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
@@ -58,11 +59,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
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_RESTART_REMIND_THREAD = 3; // 重启RemindThread线程
private static final int MSG_UPDATE_SERVICE_SWITCH = 4; // 更新服务开关UI(新增) private static final int MSG_UPDATE_SERVICE_SWITCH = 4; // 更新服务开关UI
// ======================== 静态成员(全局共享,严格管控生命周期)======================== // ======================== 静态成员(全局共享,严格管控生命周期)========================
public static MainActivity sMainActivity; // 全局Activity实例销毁时必须置空 private static MainActivity sMainActivity; // 全局Activity实例销毁时必须置空
private static Handler sGlobalHandler; // 全局Handler统一消息分发避免多Handler混乱 private static Handler sGlobalHandler; // 全局Handler统一消息分发
// ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减)======================== // ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减)========================
// 工具类实例(单例,避免重复初始化) // 工具类实例(单例,避免重复初始化)
@@ -71,15 +72,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
private BackgroundSourceUtils mBgSourceUtils; private BackgroundSourceUtils mBgSourceUtils;
// 应用核心实例 // 应用核心实例
private App mApplication; private App mApplication;
private MainContentView mMainContentView; // 核心视图封装类(统一管理视图) private MainContentView mMainContentView; // 核心视图封装类
// 基础视图组件 // 基础视图组件
private Toolbar mToolbar; private Toolbar mToolbar;
private ViewStub mAdsViewStub; private ViewStub mAdsViewStub;
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载) private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
// 资源与菜单 // 资源与菜单
private Menu mMenu; private Menu mMenu;
private Drawable mFrameDrawable; // 框架背景资源适配API30主题 private Drawable mFrameDrawable; // 框架背景资源
// 新增:服务控制核心Bean(本地持久化,管理服务自启动状态) // 服务控制核心Bean
private ControlCenterServiceBean mServiceControlBean; private ControlCenterServiceBean mServiceControlBean;
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)======================== // ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
@@ -97,15 +98,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 进入"); LogUtils.d(TAG, "onCreate: 进入");
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// 1. 初始化全局核心组件(Handler优先避免消息丢失 // 1. 初始化全局Handler优先初始化,避免消息丢失)
initGlobalHandler(); initGlobalHandler();
// 2. 加载布局+初始化核心流程 // 2. 加载布局+初始化核心流程
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
initPermissionUtils(); // 权限工具类(提前初始化,保障权限请求时效) initPermissionUtils();
initMainContentView(); // 核心视图封装替代原ViewHolder initMainContentView();
initCriticalView(); // 首屏核心视图Toolbar等保障首屏加载速度 initCriticalView();
initCoreUtilsAsync(); // 异步初始化工具类(避免主线程阻塞) initCoreUtilsAsync();
loadNonCriticalViewDelayed(); // 延迟加载非核心视图(广告,不影响首屏体验) loadNonCriticalViewDelayed();
LogUtils.d(TAG, "onCreate: 退出"); LogUtils.d(TAG, "onCreate: 退出");
} }
@@ -113,7 +114,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
protected void onPostCreate(Bundle savedInstanceState) { protected void onPostCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onPostCreate: 进入"); LogUtils.d(TAG, "onPostCreate: 进入");
super.onPostCreate(savedInstanceState); super.onPostCreate(savedInstanceState);
// 视图初始化完成后请求权限(避免视图未就绪导致的异常)
mPermissionUtils.startPermissionRequest(this); mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 退出"); LogUtils.d(TAG, "onPostCreate: 退出");
} }
@@ -122,19 +122,17 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
protected void onResume() { protected void onResume() {
LogUtils.d(TAG, "onResume: 进入"); LogUtils.d(TAG, "onResume: 进入");
super.onResume(); super.onResume();
// 1. 恢复背景(适配后台切前台场景,小米手机保活优化 // 恢复背景+同步服务开关UI仅本地配置
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onResume: 发送加载背景消息");
// 新增恢复时同步服务开关UI避免开关状态与实际服务状态不一致
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "onResume: 发送背景加载+服务开关更新消息");
} }
// 2. 恢复广告(非核心,容错处理) // 恢复广告
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.resumeADs(this); mADsBannerView.resumeADs(this);
LogUtils.d(TAG, "onResume: 恢复广告展示");
} }
// 3. 关键调整:应用切前台,设置RemindThread前台状态(开启提醒) // 设置RemindThread前台状态
setRemindThreadForeground(true); setRemindThreadForeground(true);
LogUtils.d(TAG, "onResume: 退出"); LogUtils.d(TAG, "onResume: 退出");
} }
@@ -143,7 +141,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
protected void onPause() { protected void onPause() {
LogUtils.d(TAG, "onPause: 进入"); LogUtils.d(TAG, "onPause: 进入");
super.onPause(); super.onPause();
// 关键调整:应用切后台,设置RemindThread后台状态(停止提醒+重置无效电量) // 设置RemindThread后台状态
setRemindThreadForeground(false); setRemindThreadForeground(false);
LogUtils.d(TAG, "onPause: 退出"); LogUtils.d(TAG, "onPause: 退出");
} }
@@ -152,40 +150,33 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
protected void onDestroy() { protected void onDestroy() {
LogUtils.d(TAG, "onDestroy: 进入"); LogUtils.d(TAG, "onDestroy: 进入");
super.onDestroy(); super.onDestroy();
// 1. 释放广告资源避免内存泄漏适配API30资源管控 // 1. 释放广告资源
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.releaseAdResources(); mADsBannerView.releaseAdResources();
mADsBannerView = null; mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 释放广告资源完成");
} }
// 2. 释放核心视图资源(调用封装类释放方法,彻底断开引用) // 2. 释放核心视图资源
if (mMainContentView != null) { if (mMainContentView != null) {
mMainContentView.releaseResources(); mMainContentView.releaseResources();
mMainContentView = null; mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 释放核心视图资源完成");
} }
// 3. 关键调整Activity销毁强制销毁RemindThread单例彻底停止线程 // 3. 销毁线程+清理Handler
RemindThread.destroyInstance(); RemindThread.destroyInstance();
LogUtils.d(TAG, "onDestroy: 强制销毁RemindThread单例完成");
// 4. 置空全局实例(杜绝内存泄漏,必须执行)
sMainActivity = null;
// 5. 清理Handler移除所有消息避免Activity销毁后回调
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null); sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null; sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 清理全局Handler完成");
} }
// 6. 释放Drawable资源断开回调辅助GC回收 // 4. 释放Drawable+置空全局实例
if (mFrameDrawable != null) { if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null); mFrameDrawable.setCallback(null);
mFrameDrawable = null; mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 释放Drawable资源完成");
} }
// 7. 置空所有辅助实例辅助GC避免残留引用 sMainActivity = null;
// 5. 置空所有辅助实例
mPermissionUtils = null; mPermissionUtils = null;
mAppConfigUtils = null; mAppConfigUtils = null;
mBgSourceUtils = null; mBgSourceUtils = null;
mServiceControlBean = null; // 新增置空服务控制Bean mServiceControlBean = null;
mMenu = null; mMenu = null;
mApplication = null; mApplication = null;
mToolbar = null; mToolbar = null;
@@ -197,32 +188,26 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
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);
// 1. 权限请求结果处理
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data); mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 2. 背景设置完成后重新加载背景 // 背景设置完成后重新加载背景
if (requestCode == REQUEST_READ_MEDIA_IMAGES) { if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送加载背景消息");
} }
} }
LogUtils.d(TAG, "onActivityResult: 退出"); LogUtils.d(TAG, "onActivityResult: 退出");
} }
// ======================== 菜单与导航方法(统一归类,用户交互入口)======================== // ======================== 菜单与导航方法 ========================
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu: 进入"); LogUtils.d(TAG, "onCreateOptionsMenu: 进入");
mMenu = menu; mMenu = menu;
// 1. 加载主题菜单
AESThemeUtil.inflateMenu(this, menu); AESThemeUtil.inflateMenu(this, menu);
// 2. 调试模式加载开发菜单+单元测试菜单
if (App.isDebugging()) { if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu); DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu); getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载开发/单元测试菜单");
} }
// 3. 加载主菜单
getMenuInflater().inflate(R.menu.toolbar_main, mMenu); getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 退出"); LogUtils.d(TAG, "onCreateOptionsMenu: 退出");
return true; return true;
@@ -231,18 +216,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@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());
// 1. 主题切换处理切换后重建Activity生效
if (AESThemeUtil.onAppThemeItemSelected(this, item)) { if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate(); recreate();
LogUtils.d(TAG, "onOptionsItemSelected: 主题切换重建Activity");
return true; return true;
} }
// 2. 开发模式菜单处理
if (DevelopUtils.onDevelopItemSelected(this, item)) { if (DevelopUtils.onDevelopItemSelected(this, item)) {
LogUtils.d(TAG, "onOptionsItemSelected: 开发菜单操作完成");
return true; return true;
} }
// 3. 主菜单逻辑分发(按功能分类,清晰易维护)
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_settings: case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class)); startActivity(new Intent(this, SettingsActivity.class));
@@ -272,31 +252,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void setupToolbar() { public void setupToolbar() {
super.setupToolbar(); super.setupToolbar();
// 主页面隐藏返回按钮(符合用户操作习惯)
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 隐藏Toolbar返回按钮");
} }
} }
// ======================== 页面交互方法(用户操作响应,统一归类)========================
@Override @Override
public void onBackPressed() { public void onBackPressed() {
// 退到后台不销毁Activity提升用户体验小米手机后台保活优化
moveTaskToBack(true); moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用退到后台"); LogUtils.d(TAG, "onBackPressed: 应用退到后台");
} }
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
// 保留系统默认按键分发逻辑,无自定义需求
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
// ======================== 核心初始化方法(按优先级排序,核心优先加载)======================== // ======================== 核心初始化方法 ========================
/**
* 初始化权限工具类(提前初始化,保障权限请求无延迟)
*/
private void initPermissionUtils() { private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: 进入"); LogUtils.d(TAG, "initPermissionUtils: 进入");
mPermissionUtils = PermissionUtils.getInstance(); mPermissionUtils = PermissionUtils.getInstance();
@@ -304,7 +276,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
/** /**
* 初始化全局Handler统一消息分发Java7显式实现避免内存泄漏) * 初始化全局Handler核心优化:弱引用+生命周期校验,杜绝内存泄漏)
*/ */
private void initGlobalHandler() { private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: 进入"); LogUtils.d(TAG, "initGlobalHandler: 进入");
@@ -312,19 +284,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sGlobalHandler = new Handler() { sGlobalHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
LogUtils.d(TAG, "handleMessage: 接收消息what=" + msg.what); // 严格校验Activity状态避免销毁后操作UI
// 消息处理前先校验Activity状态避免销毁后操作UI if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
if (sMainActivity == null || sMainActivity.isFinishing()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息处理"); LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息处理");
return; return;
} }
// 按消息类型分发逻辑 LogUtils.d(TAG, "handleMessage: 接收消息what=" + msg.what);
switch (msg.what) { switch (msg.what) {
case MSG_RELOAD_APPCONFIG: case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData(); sMainActivity.updateViewData();
break; break;
case MSG_CURRENTVALUEBATTERY: case MSG_CURRENTVALUEBATTERY:
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1); if (sMainActivity.mMainContentView != null) {
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
}
break; break;
case MSG_LOAD_BACKGROUND: case MSG_LOAD_BACKGROUND:
sMainActivity.reloadBackground(); sMainActivity.reloadBackground();
@@ -334,7 +307,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
AppConfigBean configBean = (AppConfigBean) msg.obj; AppConfigBean configBean = (AppConfigBean) msg.obj;
sMainActivity.restartRemindThread(configBean); sMainActivity.restartRemindThread(configBean);
break; break;
// 新增更新服务开关UI同步实际服务状态避免开关与服务状态不一致
case MSG_UPDATE_SERVICE_SWITCH: case MSG_UPDATE_SERVICE_SWITCH:
sMainActivity.updateServiceSwitchUI(); sMainActivity.updateServiceSwitchUI();
break; break;
@@ -347,9 +319,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "initGlobalHandler: 退出"); LogUtils.d(TAG, "initGlobalHandler: 退出");
} }
/**
* 初始化核心视图封装类统一管理视图替代原ViewHolder模式
*/
private void initMainContentView() { private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: 进入"); LogUtils.d(TAG, "initMainContentView: 进入");
View rootView = findViewById(android.R.id.content); View rootView = findViewById(android.R.id.content);
@@ -358,26 +327,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "initMainContentView: 退出"); LogUtils.d(TAG, "initMainContentView: 退出");
} }
/**
* 初始化首屏核心视图Toolbar等保障首屏加载速度优先渲染
*/
private void initCriticalView() { private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: 进入"); LogUtils.d(TAG, "initCriticalView: 进入");
sMainActivity = this; // 赋值全局实例用于Handler回调 sMainActivity = this;
// 初始化Toolbar
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
if (mToolbar != null) { if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
} }
// 初始化广告ViewStub仅初始化Stub不立即加载广告
mAdsViewStub = findViewById(R.id.stub_ads_banner); mAdsViewStub = findViewById(R.id.stub_ads_banner);
LogUtils.d(TAG, "initCriticalView: 退出"); LogUtils.d(TAG, "initCriticalView: 退出");
} }
/** /**
* 异步初始化核心工具类(子线程执行,避免主线程阻塞,提升首屏加载速度 * 异步初始化核心工具类(保留服务启停逻辑:应用启动时根据配置执行
*/ */
private void initCoreUtilsAsync() { private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: 进入"); LogUtils.d(TAG, "initCoreUtilsAsync: 进入");
@@ -385,41 +348,59 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void run() { public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动"); LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
// 子线程初始化工具类无UI操作安全执行
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);
if (mServiceControlBean == null) {
// 本地无配置,默认禁用服务(与服务初始化逻辑一致)
mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无服务控制配置,创建默认禁用配置");
}
LogUtils.d(TAG, "initCoreUtilsAsync: 核心工具类+服务控制Bean初始化完成");
// 切换主线程更新UIJava7显式runOnUiThread // 初始化服务控制Bean优先读取本地配置无则创建默认
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 创建默认服务控制配置(禁用)");
}
// 应用启动时:根据本地配置执行服务启停(仅执行一次)
if (mServiceControlBean.isEnableService()) {
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置启动服务");
}
});
}
} else {
if (ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 应用启动,根据配置停止服务");
}
});
}
}
// 切换主线程更新UI
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 切换主线程更新UI"); if (isFinishing() || isDestroyed()) {
if (isFinishing()) {
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新"); LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
return; return;
} }
// 适配API30加载Drawable(添加主题参数,避免系统警告) // 适配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();
checkServiceAsync(); // 异步检查服务状态 sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); // 加载背景 sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
// 新增初始化服务开关UI确保开关状态与本地配置一致
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
} }
}); });
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束"); LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
@@ -428,49 +409,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "initCoreUtilsAsync: 退出"); LogUtils.d(TAG, "initCoreUtilsAsync: 退出");
} }
/**
* 延迟加载非核心视图广告延迟500ms加载不影响首屏体验
*/
private void loadNonCriticalViewDelayed() { private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入"); LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入");
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
if (isFinishing()) { if (isFinishing() || isDestroyed()) {
LogUtils.w(TAG, "loadNonCriticalViewDelayed: Activity已销毁跳过广告加载");
return; return;
} }
loadAdsView(); // 加载广告视图 loadAdsView();
} }
}, DELAY_LOAD_NON_CRITICAL); }, DELAY_LOAD_NON_CRITICAL);
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出"); LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出");
} }
// ======================== 视图操作方法UI更新统一归类======================== // ======================== 视图操作方法 ========================
/**
* 加载广告视图(非核心,容错处理,避免广告加载失败影响主功能)
*/
private void loadAdsView() { private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 进入"); LogUtils.d(TAG, "loadAdsView: 进入");
if (mAdsViewStub == null) { if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空,加载失败"); LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空");
return; return;
} }
if (mADsBannerView == null) { if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate(); View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner); mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: 广告视图加载完成");
} }
LogUtils.d(TAG, "loadAdsView: 退出"); LogUtils.d(TAG, "loadAdsView: 退出");
} }
/**
* 更新视图数据调用核心视图封装类方法统一更新UI
*/
private void updateViewData() { private void updateViewData() {
LogUtils.d(TAG, "updateViewData: 进入"); LogUtils.d(TAG, "updateViewData: 进入");
if (mMainContentView == null || mFrameDrawable == null) { if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空,跳过更新"); LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空");
return; return;
} }
mMainContentView.updateViewData(mFrameDrawable); mMainContentView.updateViewData(mFrameDrawable);
@@ -478,234 +448,145 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "updateViewData: 退出"); LogUtils.d(TAG, "updateViewData: 退出");
} }
/**
* 重新加载背景(适配背景切换,小米手机图片加载优化,容错处理)
*/
private void reloadBackground() { private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: 进入"); LogUtils.d(TAG, "reloadBackground: 进入");
if (mMainContentView == null || mBgSourceUtils == null) { if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空,跳过加载"); LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空");
return; return;
} }
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean); mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
LogUtils.d(TAG, "reloadBackground: 加载自定义背景完成");
} else { } else {
LogUtils.e(TAG, "reloadBackground: 无自定义背景,加载默认背景");
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background); mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
} }
LogUtils.d(TAG, "reloadBackground: 退出"); LogUtils.d(TAG, "reloadBackground: 退出");
} }
/**
* 设置主布局背景颜色适配背景配置API30安全防护
*/
private void setMainLayoutBackgroundColor() { private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入"); LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入");
if (isFinishing() || mMainContentView == null || mBgSourceUtils == null) { if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效,跳过设置"); LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效");
return; return;
} }
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
int bgColor = currentBgBean.getPixelColor(); mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
mMainContentView.mainLayout.setBackgroundColor(bgColor);
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局颜色设置完成");
} }
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出"); LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出");
} }
/** /**
* 新增:更新服务开关UI同步本地配置+实际服务状态」,避免开关与服务状态不一致 * 更新服务开关UI同步本地配置,不校验服务状态)
*/ */
private void updateServiceSwitchUI() { private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI: 进入"); LogUtils.d(TAG, "updateServiceSwitchUI: 进入");
if (mMainContentView == null || mServiceControlBean == null) { if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空,跳过更新"); LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空");
return; return;
} }
// 开关状态 = 本地服务控制配置启用状态(自启动状态) // 仅读取本地配置状态,不涉及服务状态校验
boolean isServiceEnabled = mServiceControlBean.isEnableService(); boolean configEnabled = mServiceControlBean.isEnableService();
// 禁用开关点击避免更新UI时触发重复回调 LogUtils.d(TAG, "updateServiceSwitchUI: 本地配置状态=" + configEnabled);
// 仅更新UI开关状态
mMainContentView.setServiceSwitchEnabled(false); mMainContentView.setServiceSwitchEnabled(false);
// 更新开关状态 mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchChecked(isServiceEnabled);
// 启用开关点击
mMainContentView.setServiceSwitchEnabled(true); mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI更新完成当前状态=" + isServiceEnabled);
LogUtils.d(TAG, "updateServiceSwitchUI: 退出"); LogUtils.d(TAG, "updateServiceSwitchUI: 退出");
} }
// ======================== 服务与线程管理方法(业务核心,统一归类)======================== // ======================== 服务与线程管理方法 ========================
/** /**
* 异步检查服务状态子线程执行避免主线程阻塞适配API30前台服务规范 * 重启提醒线程仅由配置变更触发不与UI开关联动
*/
private void checkServiceAsync() {
LogUtils.d(TAG, "checkServiceAsync: 进入");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "checkServiceAsync: 异步线程启动");
if (mAppConfigUtils == null || mServiceControlBean == null || isFinishing()) {
LogUtils.e(TAG, "checkServiceAsync: 配置工具类/服务控制Bean/Activity无效跳过检查");
return;
}
// 服务启用本地配置且未运行时启动前台服务API30必须前台服务小米保活优化
if (mServiceControlBean.isEnableService() && !ServiceUtils.isServiceAlive(getActivity(), ControlCenterService.class.getName())) {
LogUtils.d(TAG, "checkServiceAsync: 服务未运行,启动前台服务");
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
ControlCenterService.startControlCenterService(getActivity());
}
}
});
}
LogUtils.d(TAG, "checkServiceAsync: 异步线程结束");
}
}).start();
LogUtils.d(TAG, "checkServiceAsync: 退出");
}
/**
* 重启RemindThread线程通过服务统一管理保障线程安全适配API30服务规范
*/ */
private void restartRemindThread(AppConfigBean configBean) { private void restartRemindThread(AppConfigBean configBean) {
LogUtils.d(TAG, "restartRemindThread: 进入"); LogUtils.d(TAG, "restartRemindThread: 进入");
if (configBean == null || mServiceControlBean == null) { if (configBean == null || mServiceControlBean == null) {
LogUtils.e(TAG, "restartRemindThread: 配置为空/服务控制Bean为空,跳过重启"); LogUtils.e(TAG, "restartRemindThread: 配置/服务控制Bean为空");
return; return;
} }
// 服务未启用时,不重启线程(直接返回)
if (!mServiceControlBean.isEnableService()) { if (!mServiceControlBean.isEnableService()) {
LogUtils.w(TAG, "restartRemindThread: 服务已禁用,跳过线程重启"); LogUtils.w(TAG, "restartRemindThread: 服务已禁用,跳过线程重启");
return; return;
} }
// 服务未运行时,先启动服务 if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) { ControlCenterService.startControlCenterService(getApplicationContext());
ControlCenterService.startControlCenterService(this);
LogUtils.d(TAG, "restartRemindThread: 服务未运行,先启动服务");
} }
// 关键优化:重启前先销毁旧线程,避免线程复用导致的状态脏数据
RemindThread.destroyInstance(); RemindThread.destroyInstance();
LogUtils.d(TAG, "restartRemindThread: 销毁旧线程完成,准备启动新线程"); ControlCenterService.updateStatus(getApplicationContext(), configBean);
// 发送重启指令到服务通过Intent传递最新配置
ControlCenterService.updateStatus(this, configBean);
LogUtils.d(TAG, "restartRemindThread: 发送线程重启指令到服务完成");
LogUtils.d(TAG, "restartRemindThread: 退出"); LogUtils.d(TAG, "restartRemindThread: 退出");
} }
/** /**
* 关键新增设置RemindThread前台/后台状态(核心修复无限提醒问题 * 设置线程前后台状态(依赖服务运行状态
* @param isForeground true=前台开启提醒false=后台(停止提醒)
*/ */
private void setRemindThreadForeground(boolean isForeground) { private void setRemindThreadForeground(boolean isForeground) {
LogUtils.d(TAG, "setRemindThreadForeground: 进入,前台状态=" + isForeground); LogUtils.d(TAG, "setRemindThreadForeground: 进入,前台状态=" + isForeground);
// 服务未运行时,跳过状态设置(线程未启动) if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
LogUtils.w(TAG, "setRemindThreadForeground: 服务未运行,跳过状态设置"); LogUtils.w(TAG, "setRemindThreadForeground: 服务未运行,跳过状态设置");
return; return;
} }
// 调用RemindThread新增方法设置前台状态线程安全
try { try {
RemindThread.getInstance(this, null).setAppForeground(isForeground); RemindThread.getInstance(getApplicationContext(), null).setAppForeground(isForeground);
LogUtils.d(TAG, "setRemindThreadForeground: RemindThread状态设置完成");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// 首次启动时Handler可能未就绪容错处理服务会后续同步状态 LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化", e);
LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化完成,后续服务会同步状态", e);
} }
LogUtils.d(TAG, "setRemindThreadForeground: 退出"); LogUtils.d(TAG, "setRemindThreadForeground: 退出");
} }
/** /**
* 新增:切换服务启用/禁用状态(核心修复:持久化配置+启停服务+更新UI+重启线程 * 切换服务启用状态仅持久化本地配置点击UI开关时不联动服务启停
* @param isEnable true=启用服务(自启动+启动服务false=禁用服务(停止服务)
*/ */
private void toggleServiceEnableState(boolean isEnable) { private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable); LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable);
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空,切换失败"); LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空");
return; return;
} }
// 1. 更新本地服务控制配置持久化,实现自启动) // 更新本地配置持久化
mServiceControlBean.setIsEnableService(isEnable); mServiceControlBean.setIsEnableService(isEnable);
ControlCenterService.updateServiceControlConfig(this, mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 服务控制配置已持久化,自启动状态=" + isEnable); LogUtils.d(TAG, "toggleServiceEnableState: 本地服务控制配置已持久化,状态=" + isEnable);
// 2. 启停服务通过服务静态方法适配API30前台服务规范 // 仅更新UI无服务启停操作
if (isEnable) {
// 启用:启动前台服务+检查电池优化(避免服务被杀死)
ControlCenterService.startControlCenterService(this);
ControlCenterService.checkIgnoreBatteryOptimization(this);
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动,已引导忽略电池优化");
} else {
// 禁用:停止服务(服务内部会自动停止线程+释放资源)
ControlCenterService.stopControlCenterService(this);
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
}
// 3. 服务启用时,重启线程(确保线程使用最新配置)
if (isEnable && mAppConfigUtils != null && mAppConfigUtils.mAppConfigBean != null) {
sendRestartRemindThreadMessage();
}
// 4. 更新服务开关UI确保开关状态与实际服务状态一致
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "toggleServiceEnableState: 服务状态切换完成");
LogUtils.d(TAG, "toggleServiceEnableState: 退出"); LogUtils.d(TAG, "toggleServiceEnableState: 退出");
} }
// ======================== 页面跳转方法(封装逻辑,减少冗余)======================== // ======================== 页面跳转方法 ========================
/**
* 启动关于页面(封装跳转逻辑,统一参数传递,便于维护)
*/
private void startAboutActivity() { private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: 进入"); LogUtils.d(TAG, "startAboutActivity: 进入");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class); Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo(); APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo); aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class); WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
LogUtils.d(TAG, "startAboutActivity: 启动关于页面完成");
LogUtils.d(TAG, "startAboutActivity: 退出"); LogUtils.d(TAG, "startAboutActivity: 退出");
} }
// ======================== 消息发送方法(统一封装,避免冗余,保障消息安全)======================== // ======================== 消息发送方法 ========================
/**
* 发送重启RemindThread线程消息携带最新配置确保线程使用最新参数
*/
private void sendRestartRemindThreadMessage() { private void sendRestartRemindThreadMessage() {
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入"); LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入");
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) { if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
LogUtils.e(TAG, "sendRestartRemindThreadMessage: Handler/配置为空,跳过发送"); LogUtils.e(TAG, "sendRestartRemindThreadMessage: 环境无效");
return; return;
} }
// 复用Message避免内存抖动优化性能
Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD); Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD);
msg.obj = mAppConfigUtils.mAppConfigBean; msg.obj = mAppConfigUtils.mAppConfigBean;
sGlobalHandler.sendMessage(msg); sGlobalHandler.sendMessage(msg);
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 发送线程重启消息完成");
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出"); LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出");
} }
// ======================== 静态工具方法(全局调用,统一入口)======================== // ======================== 静态工具方法 ========================
/**
* 重新加载应用配置(全局调用,触发视图更新)
*/
public static void reloadAppConfig() { public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: 发送重新加载配置消息"); LogUtils.d(TAG, "reloadAppConfig: 发送配置更新消息");
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG); sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
} }
} }
/**
* 发送当前电量更新消息全局调用实时更新UI
*/
public static void sendCurrentBatteryValueMessage(int value) { public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value + ",发送更新消息"); LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value);
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY); Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value; msg.arg1 = value;
@@ -713,14 +594,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
} }
// ======================== 辅助工具方法(封装重复逻辑,提升复用性)======================== // ======================== 辅助工具方法 ========================
/**
* 从URI获取图片真实路径适配API30媒体存储权限Java7显式Cursor操作避免资源泄漏
*/
private String getRealPathFromUri(Uri contentUri) { private String getRealPathFromUri(Uri contentUri) {
LogUtils.d(TAG, "getRealPathFromUri: 进入"); LogUtils.d(TAG, "getRealPathFromUri: 进入");
if (contentUri == null) { if (contentUri == null) {
LogUtils.e(TAG, "getRealPathFromUri: URI为空,获取失败"); LogUtils.e(TAG, "getRealPathFromUri: URI为空");
return null; return null;
} }
String realPath = null; String realPath = null;
@@ -732,24 +610,16 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA); int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (columnIndex > -1) { if (columnIndex > -1) {
realPath = cursor.getString(columnIndex); realPath = cursor.getString(columnIndex);
LogUtils.d(TAG, "getRealPathFromUri: 获取图片路径=" + realPath);
} }
} }
} finally { } finally {
// Java7必须显式关闭Cursor避免资源泄漏无try-with-resources语法
cursor.close(); cursor.close();
} }
} }
if (realPath == null) { LogUtils.d(TAG, "getRealPathFromUri: 退出,路径=" + realPath);
LogUtils.e(TAG, "getRealPathFromUri: 获取图片路径失败");
}
LogUtils.d(TAG, "getRealPathFromUri: 退出");
return realPath; return realPath;
} }
/**
* 生成默认应用信息(关于页面使用,封装参数赋值,便于维护)
*/
private APPInfo genDefaultAppInfo() { private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 进入"); LogUtils.d(TAG, "genDefaultAppInfo: 进入");
String branchName = "powerbell"; String branchName = "powerbell";
@@ -764,12 +634,11 @@ 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: 退出"); LogUtils.d(TAG, "genDefaultAppInfo: 退出");
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);
@@ -785,7 +654,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void onServiceSwitchChanged(boolean isChecked) { public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked); LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
// 核心修复:点击服务开关,触发「配置持久化+服务启停+UI更新」全链路逻辑 // 仅更新本地配置,不触发服务启停
toggleServiceEnableState(isChecked); toggleServiceEnableState(isChecked);
} }

View File

@@ -1,6 +1,7 @@
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,24 +11,26 @@ 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 android.text.TextUtils;
import java.io.Serializable; import androidx.core.app.NotificationCompat;
import java.util.List;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
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;
import cc.winboll.studio.powerbell.models.NotificationMessage; import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.threads.RemindThread; import cc.winboll.studio.powerbell.threads.RemindThread;
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils; import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import java.io.Serializable;
import java.util.List;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 15:48 * @Date 2025/12/17 15:48
* @Describe 电池提醒核心服务:通过本地持久化 ControlCenterServiceBean 控制自启动,统一管理线程、通知、配置适配Java7+API30 * @Describe 电池提醒核心服务:修复前台服务超时异常优先在onCreate发送通知适配Java7+API36
*/ */
public class ControlCenterService extends Service { public class ControlCenterService extends Service {
// ================================== 静态常量(置顶统一管理,避免魔法值)================================= // ================================== 静态常量(置顶统一管理,避免魔法值)=================================
private 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";
@@ -52,7 +55,7 @@ public class ControlCenterService extends Service {
private boolean mIsDestroyed = false; // 服务销毁标记 private boolean mIsDestroyed = false; // 服务销毁标记
private final Object mServiceLock = new Object(); // 全局并发锁 private final Object mServiceLock = new Object(); // 全局并发锁
// ================================== 服务生命周期方法onCreate→onStartCommand→onDestroy================================= // ================================== 服务生命周期方法(核心修复:onCreate优先发送通知=================================
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
@@ -60,7 +63,11 @@ public class ControlCenterService extends Service {
synchronized (mServiceLock) { synchronized (mServiceLock) {
isServiceRunning = true; isServiceRunning = true;
mIsDestroyed = false; mIsDestroyed = false;
// 初始化服务控制配置:优先读取本地持久化配置,无则创建默认禁用配置
// ================================== 【修复点1最优先执行前台通知发送】=================================
initForegroundNotificationImmediately();
// 原有逻辑:读取本地服务控制配置
mServiceControlBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class); mServiceControlBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false); mServiceControlBean = new ControlCenterServiceBean(false);
@@ -70,7 +77,7 @@ public class ControlCenterService extends Service {
LogUtils.d(TAG, "onCreate: 从本地读取服务控制配置,启用状态=" + mServiceControlBean.isEnableService()); LogUtils.d(TAG, "onCreate: 从本地读取服务控制配置,启用状态=" + mServiceControlBean.isEnableService());
} }
} }
LogUtils.d(TAG, "onCreate: 服务创建完成,当前服务控制状态:" + (mServiceControlBean.isEnableService() ? "启用" : "禁用")); LogUtils.d(TAG, "onCreate: 服务创建完成,前台通知已发送,当前服务控制状态:" + (mServiceControlBean.isEnableService() ? "启用" : "禁用"));
} }
@Override @Override
@@ -82,9 +89,9 @@ public class ControlCenterService extends Service {
synchronized (mServiceLock) { synchronized (mServiceLock) {
if (mServiceControlBean.isEnableService()) { if (mServiceControlBean.isEnableService()) {
LogUtils.d(TAG, "onStartCommand: 服务已启用,执行核心逻辑"); LogUtils.d(TAG, "onStartCommand: 服务已启用,执行核心逻辑");
// 启用状态:处理指令+绑定前台通知+启动业务返回START_STICKY回收后重启 // 启用状态:处理指令+启动业务返回START_STICKY回收后重启
handleExternalCommand(intent); handleExternalCommand(intent);
rebindForegroundNotify(); // ================================== 【修复点2删除rebindForegroundNotify(),避免重复调用】=================================
initServiceBusinessIfNeed(); // 按需初始化业务(避免重复初始化) initServiceBusinessIfNeed(); // 按需初始化业务(避免重复初始化)
// 新增:业务初始化完成后,同步应用前台状态到线程(防止状态丢失) // 新增:业务初始化完成后,同步应用前台状态到线程(防止状态丢失)
syncAppForegroundStateToThread(); syncAppForegroundStateToThread();
@@ -123,6 +130,54 @@ public class ControlCenterService extends Service {
return null; // 无需绑定服务返回null return null; // 无需绑定服务返回null
} }
// ================================== 【新增核心方法:优先发送前台通知,带兜底方案】=================================
/**
* 独立初始化前台通知并立即发送不依赖任何业务逻辑确保5秒内完成startForeground()
* 防止工具类异常导致超时,内置兜底方案
*/
private void initForegroundNotificationImmediately() {
LogUtils.d(TAG, "initForegroundNotificationImmediately: 强制初始化前台通知");
try {
// 1. 初始化通知工具类
if (mNotificationManager == null) {
mNotificationManager = new NotificationManagerUtils(this);
}
// 2. 构建极简前台通知模型(不依赖业务配置,确保最快速度发送)
if (mForegroundNotifyMsg == null) {
mForegroundNotifyMsg = new NotificationMessage();
mForegroundNotifyMsg.setTitle("电池监测服务");
mForegroundNotifyMsg.setContent("后台运行中");
mForegroundNotifyMsg.setRemindMSG("service_running");
}
// 3. 立即调用工具类发送前台通知
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
LogUtils.d(TAG, "initForegroundNotificationImmediately: 前台通知发送成功ID=" + NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE);
} catch (Exception e) {
LogUtils.e(TAG, "initForegroundNotificationImmediately: 工具类发送失败,执行兜底方案", e);
// 兜底方案绕过工具类直接构建Notification调用startForeground
fallbackStartForeground();
}
}
/**
* 前台通知兜底方案:当工具类异常时,直接创建通知,确保不触发超时异常
*/
private void fallbackStartForeground() {
try {
Notification notification = new NotificationCompat.Builder(this, NotificationManagerUtils.CHANNEL_ID_FOREGROUND)
.setContentTitle("电池监测服务")
.setContentText("后台运行中")
.setSmallIcon(R.drawable.ic_launcher) // 必须设置小图标,否则通知不显示
.setPriority(NotificationCompat.PRIORITY_LOW)
.build();
// 直接调用startForeground不依赖任何外部工具
startForeground(NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE, notification);
LogUtils.d(TAG, "fallbackStartForeground: 兜底前台通知发送成功");
} catch (Exception e) {
LogUtils.e(TAG, "fallbackStartForeground: 兜底发送失败,服务会被系统强制杀死", e);
}
}
// ================================== 核心服务控制配置本地持久化读写替代Intent传递================================= // ================================== 核心服务控制配置本地持久化读写替代Intent传递=================================
/** /**
* 读取本地最新服务控制配置(实时同步,确保与用户设置一致) * 读取本地最新服务控制配置(实时同步,确保与用户设置一致)
@@ -203,6 +258,7 @@ public class ControlCenterService extends Service {
// ================================== 核心业务初始化方法(按依赖顺序排列)================================= // ================================== 核心业务初始化方法(按依赖顺序排列)=================================
/** /**
* 初始化通知管理工具类,构建前台保活通知模型 * 初始化通知管理工具类,构建前台保活通知模型
* 【修复点3移除内部的startForegroundNotifyImmediately()调用,避免重复发送】
*/ */
private void initNotificationManager() { private void initNotificationManager() {
LogUtils.d(TAG, "initNotificationManager: 初始化通知工具类"); LogUtils.d(TAG, "initNotificationManager: 初始化通知工具类");
@@ -215,8 +271,7 @@ public class ControlCenterService extends Service {
mForegroundNotifyMsg.setTitle("电池提醒服务运行中"); mForegroundNotifyMsg.setTitle("电池提醒服务运行中");
mForegroundNotifyMsg.setContent("后台持续监测电池状态,确保提醒及时"); mForegroundNotifyMsg.setContent("后台持续监测电池状态,确保提醒及时");
mForegroundNotifyMsg.setRemindMSG("service_running"); mForegroundNotifyMsg.setRemindMSG("service_running");
// 启动前台保活通知 // 移除此处不再发送通知通知已在onCreate中发送
startForegroundNotifyImmediately();
} }
LogUtils.d(TAG, "initNotificationManager: 通知工具类初始化完成"); LogUtils.d(TAG, "initNotificationManager: 通知工具类初始化完成");
} catch (Exception e) { } catch (Exception e) {
@@ -226,6 +281,7 @@ public class ControlCenterService extends Service {
/** /**
* 立即启动前台保活通知API26+ 前台服务必需) * 立即启动前台保活通知API26+ 前台服务必需)
* 注当前仅作为备用方法实际已在initForegroundNotificationImmediately中调用
*/ */
private void startForegroundNotifyImmediately() { private void startForegroundNotifyImmediately() {
LogUtils.d(TAG, "startForegroundNotifyImmediately: 启动前台保活通知"); LogUtils.d(TAG, "startForegroundNotifyImmediately: 启动前台保活通知");
@@ -243,7 +299,7 @@ public class ControlCenterService extends Service {
} }
/** /**
* 重新绑定前台通知(onStartCommand触发防止保活状态丢失 * 重新绑定前台通知(已删除调用防止重复执行startForeground
*/ */
private void rebindForegroundNotify() { private void rebindForegroundNotify() {
if (mNotificationManager == null || mNotificationManager.getForegroundServiceNotify() == null) { if (mNotificationManager == null || mNotificationManager.getForegroundServiceNotify() == null) {
@@ -447,9 +503,7 @@ public class ControlCenterService extends Service {
LogUtils.w(TAG, "handleExternalCommand: 服务已禁用,忽略线程重启指令"); LogUtils.w(TAG, "handleExternalCommand: 服务已禁用,忽略线程重启指令");
} }
} }
} } else if (ACTION_SYNC_APP_FOREGROUND_STATE.equals(action)) {
// 2. 新增:处理应用前台/后台状态同步指令MainActivity触发
else if (ACTION_SYNC_APP_FOREGROUND_STATE.equals(action)) {
boolean isForeground = intent.getBooleanExtra(EXTRA_APP_FOREGROUND_STATE, false); boolean isForeground = intent.getBooleanExtra(EXTRA_APP_FOREGROUND_STATE, false);
synchronized (mServiceLock) { synchronized (mServiceLock) {
mIsAppForeground = isForeground; mIsAppForeground = isForeground;
@@ -514,9 +568,10 @@ public class ControlCenterService extends Service {
LogUtils.d(TAG, "clearAllReferences: 所有引用已置空"); LogUtils.d(TAG, "clearAllReferences: 所有引用已置空");
} }
// ================================== 静态工具方法(新增前台状态同步入口,完善保活优化================================= // ================================== 静态工具方法(修复启停逻辑颠倒问题=================================
/** /**
* 启动服务静态入口从本地读取控制配置显式绑定包名适配API30+ * 启动服务静态入口从本地读取控制配置显式绑定包名适配API30+
* 【修复点4统一使用startForegroundService适配API26+】
*/ */
public static void startControlCenterService(Context context) { public static void startControlCenterService(Context context) {
LogUtils.d(TAG, "startControlCenterService: 启动服务入口"); LogUtils.d(TAG, "startControlCenterService: 启动服务入口");
@@ -524,26 +579,14 @@ public class ControlCenterService extends Service {
LogUtils.e(TAG, "startControlCenterService: Context为空启动失败"); LogUtils.e(TAG, "startControlCenterService: Context为空启动失败");
return; return;
} }
if (isServiceRunning(context, ControlCenterService.class)) {
LogUtils.d(TAG, "startControlCenterService: 服务已运行,同步本地控制配置");
// 服务已运行触发onStartCommand同步最新配置
sendSyncConfigCommand(context);
return;
}
Intent intent = new Intent(context, ControlCenterService.class); Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName()); // 修复API26+必须调用startForegroundService避免系统异常
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try { context.startForegroundService(intent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { } else {
context.startForegroundService(intent); context.startService(intent);
} else {
context.startService(intent);
}
LogUtils.d(TAG, "startControlCenterService: 服务启动指令发送成功");
} catch (Exception e) {
LogUtils.e(TAG, "startControlCenterService: 启动服务异常", e);
} }
LogUtils.d(TAG, "startControlCenterService: 服务启动指令发送成功");
} }
/** /**
@@ -555,19 +598,14 @@ public class ControlCenterService extends Service {
LogUtils.e(TAG, "stopControlCenterService: Context为空停止失败"); LogUtils.e(TAG, "stopControlCenterService: Context为空停止失败");
return; return;
} }
if (!isServiceRunning(context, ControlCenterService.class)) {
LogUtils.d(TAG, "stopControlCenterService: 服务未运行,跳过停止");
return;
}
Intent intent = new Intent(context, ControlCenterService.class); Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName());
context.stopService(intent); context.stopService(intent);
LogUtils.d(TAG, "stopControlCenterService: 服务停止指令发送成功"); LogUtils.d(TAG, "stopControlCenterService: 服务停止指令发送成功");
} }
/** /**
* 新增:更新服务控制配置(本地持久化,动态切换服务启用/禁用状态) * 新增:更新服务控制配置(本地持久化,动态切换服务启用/禁用状态)
* 【修复点5修复启停逻辑颠倒问题】
*/ */
public static void updateServiceControlConfig(Context context, ControlCenterServiceBean controlBean) { public static void updateServiceControlConfig(Context context, ControlCenterServiceBean controlBean) {
LogUtils.d(TAG, "updateServiceControlConfig: 更新服务控制配置,新状态=" + controlBean.isEnableService()); LogUtils.d(TAG, "updateServiceControlConfig: 更新服务控制配置,新状态=" + controlBean.isEnableService());
@@ -580,32 +618,14 @@ public class ControlCenterService extends Service {
ControlCenterServiceBean.saveBean(context, controlBean); ControlCenterServiceBean.saveBean(context, controlBean);
LogUtils.d(TAG, "updateServiceControlConfig: 控制配置已持久化"); LogUtils.d(TAG, "updateServiceControlConfig: 控制配置已持久化");
// 第二步:若服务已运行,触发同步(让服务立即生效 // 第二步:启停服务(修复:启用则启动,禁用则停止
if (isServiceRunning(context, ControlCenterService.class)) { if (controlBean.isEnableService()) {
sendSyncConfigCommand(context); stopControlCenterService(context);
LogUtils.d(TAG, "updateServiceControlConfig: 服务已运行,已触发配置同步");
} else {
// 服务未运行,按需启动服务(根据新配置决定是否启用业务)
startControlCenterService(context); startControlCenterService(context);
LogUtils.d(TAG, "updateServiceControlConfig: 服务未运行,已启动服务并加载新配置"); LogUtils.d(TAG, "updateServiceControlConfig: 服务已设置启动");
} } else {
} stopControlCenterService(context);
LogUtils.d(TAG, "updateServiceControlConfig: 服务已设置停止");
/**
* 新增:发送配置同步指令(触发服务读取本地最新配置,立即生效)
*/
private static void sendSyncConfigCommand(Context context) {
Intent intent = new Intent(context, ControlCenterService.class);
intent.setPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
} catch (Exception e) {
LogUtils.e(TAG, "sendSyncConfigCommand: 发送同步指令异常", e);
} }
} }

View File

@@ -66,6 +66,8 @@ public class MainContentView {
// 配置变更确认对话框(单例复用,避免重复创建) // 配置变更确认对话框(单例复用,避免重复创建)
private AlertDialog mConfigConfirmDialog; private AlertDialog mConfigConfirmDialog;
// 对话框 Builder核心新增解决 setMessage 不生效问题)
private AlertDialog.Builder mDialogBuilder;
// 临时存储变更数据(对话框确认前缓存,取消时恢复) // 临时存储变更数据(对话框确认前缓存,取消时恢复)
private TempConfigData mTempConfigData; private TempConfigData mTempConfigData;
// 对话框状态锁(避免快速点击重复弹窗) // 对话框状态锁(避免快速点击重复弹窗)
@@ -116,7 +118,7 @@ public class MainContentView {
// 执行核心初始化流程(按顺序执行,避免依赖空指针) // 执行核心初始化流程(按顺序执行,避免依赖空指针)
bindViews(rootView); bindViews(rootView);
initBatteryDrawables(); initBatteryDrawables();
initConfirmDialog(); initConfirmDialog(); // 先初始化对话框,再绑定监听
bindViewListeners(); bindViewListeners();
LogUtils.d(TAG, "constructor: 整体初始化完成"); LogUtils.d(TAG, "constructor: 整体初始化完成");
@@ -176,7 +178,7 @@ public class MainContentView {
} }
/** /**
* 初始化配置变更确认对话框(单例复用,无模式,点击外部关闭,适配 API30 对话框机制 * 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题
*/ */
private void initConfirmDialog() { private void initConfirmDialog() {
LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框"); LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框");
@@ -185,29 +187,31 @@ public class MainContentView {
return; return;
} }
// 构建无模式对话框(点击外部可关闭,取消改动 // 1. 初始化 Builder核心后续通过 Builder 更新消息
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); mDialogBuilder = new AlertDialog.Builder(mContext);
builder.setTitle("配置变更确认"); mDialogBuilder.setTitle("配置变更确认");
// 优化:区分服务开关/普通配置,显示不同提示语(提升用户体验) mDialogBuilder.setMessage("是否确认修改当前配置?");
builder.setMessage("是否确认修改当前配置?");
// 确定按钮:保存配置+回调+更新视图 // 确定按钮:保存配置+回调+更新视图
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { mDialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
confirmConfigChange(); // 确认变更,保存配置 confirmConfigChange(); // 确认变更,保存配置
dialog.dismiss(); dialog.dismiss();
} }
}); });
// 取消按钮:恢复原始配置(补充物理取消按钮,提升用户体验) // 取消按钮:恢复原始配置(补充物理取消按钮,提升用户体验)
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { mDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
cancelConfigChange(); // 取消变更,恢复原始值 cancelConfigChange(); // 取消变更,恢复原始值
dialog.dismiss(); dialog.dismiss();
} }
}); });
// 对话框外部点击监听:关闭对话框+恢复原始配置 // 对话框外部点击监听:关闭对话框+恢复原始配置
builder.setOnCancelListener(new DialogInterface.OnCancelListener() { mDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override @Override
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
cancelConfigChange(); // 取消变更,恢复原始值 cancelConfigChange(); // 取消变更,恢复原始值
@@ -215,8 +219,8 @@ public class MainContentView {
} }
}); });
// 初始化对话框实例(设置可取消,支持外部点击关闭) // 2. 初始化对话框实例(设置可取消,支持外部点击关闭)
mConfigConfirmDialog = builder.create(); mConfigConfirmDialog = mDialogBuilder.create();
mConfigConfirmDialog.setCancelable(true); mConfigConfirmDialog.setCancelable(true);
mConfigConfirmDialog.setCanceledOnTouchOutside(true); mConfigConfirmDialog.setCanceledOnTouchOutside(true);
LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成"); LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成");
@@ -246,6 +250,7 @@ public class MainContentView {
} }
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress); mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress); LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
} }
@@ -277,6 +282,7 @@ public class MainContentView {
if (originalValue == newValue) return; if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue); mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
} }
@@ -297,6 +303,7 @@ public class MainContentView {
} }
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress); mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress); LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
} }
@@ -328,6 +335,7 @@ public class MainContentView {
if (originalValue == newValue) return; if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue); mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
} }
@@ -335,19 +343,21 @@ public class MainContentView {
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成"); LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成");
} }
// 服务总开关监听(核心优化:从 AppConfig 改为读取服务控制Bean确保状态一致 // 服务总开关监听(核心优化:逻辑与其他控件完全对齐
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setOnClickListener(new View.OnClickListener() { swEnableService.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
// 关键调整服务开关状态从服务控制Bean读取而非AppConfig // 从服务控制Bean读取原始状态确保与实际一致
boolean originalValue = getServiceEnableState(); boolean originalValue = getServiceEnableState();
boolean newValue = ((Switch) v).isChecked(); boolean newValue = ((Switch) v).isChecked();
// 状态无变化,不处理 // 状态无变化,不处理
if (originalValue == newValue) return; if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框(优化:服务开关弹窗提示语差异化) // 缓存变更数据
mTempConfigData = new TempConfigData(CHANGE_TYPE_SERVICE_SWITCH, originalValue, newValue); mTempConfigData = new TempConfigData(CHANGE_TYPE_SERVICE_SWITCH, originalValue, newValue);
// 更新差异化提示语
updateDialogMessageByChangeType(); updateDialogMessageByChangeType();
// 显示确认对话框
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
} }
@@ -376,7 +386,7 @@ public class MainContentView {
int currentVal = mAppConfigUtils.getCurrentBatteryValue(); int currentVal = mAppConfigUtils.getCurrentBatteryValue();
boolean chargeEnable = mAppConfigUtils.isChargeReminderEnabled(); boolean chargeEnable = mAppConfigUtils.isChargeReminderEnabled();
boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled(); boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled();
// 关键调整:服务开关状态从服务控制Bean读取确保与服务实际状态一致 // 从服务控制Bean读取状态,确保UI与实际一致
boolean serviceEnable = getServiceEnableState(); boolean serviceEnable = getServiceEnableState();
LogUtils.d(TAG, "updateViewData: 配置数据读取完成charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal + ", serviceEnable=" + serviceEnable); LogUtils.d(TAG, "updateViewData: 配置数据读取完成charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal + ", serviceEnable=" + serviceEnable);
@@ -424,7 +434,7 @@ public class MainContentView {
if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable); if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable);
LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成"); LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成");
// 服务开关+提示文本更新(核心调整使用服务控制Bean状态 // 服务开关+提示文本更新(确保状态准确
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setChecked(serviceEnable); swEnableService.setChecked(serviceEnable);
swEnableService.setText(mContext.getString(R.string.txt_aboveswitch)); swEnableService.setText(mContext.getString(R.string.txt_aboveswitch));
@@ -471,6 +481,8 @@ public class MainContentView {
mConfigConfirmDialog.setOnCancelListener(null); mConfigConfirmDialog.setOnCancelListener(null);
mConfigConfirmDialog = null; mConfigConfirmDialog = null;
} }
// 释放 Builder
mDialogBuilder = null;
// 释放临时数据 // 释放临时数据
mTempConfigData = null; mTempConfigData = null;
@@ -506,7 +518,7 @@ public class MainContentView {
} }
/** /**
* 新增:设置服务开关启用状态(外部调用,同步 UI 与服务状态,适配 Activity 视图刷新) * 设置服务开关启用状态(外部调用,同步 UI 与服务状态,适配 Activity 视图刷新)
* @param enabled 服务启用状态 * @param enabled 服务启用状态
*/ */
public void setServiceSwitchChecked(boolean enabled) { public void setServiceSwitchChecked(boolean enabled) {
@@ -517,7 +529,7 @@ public class MainContentView {
} }
/** /**
* 新增:设置服务开关点击状态(外部调用,避免更新 UI 时触发重复回调) * 设置服务开关点击状态(外部调用,避免更新 UI 时触发重复回调)
* @param enabled 是否允许点击 * @param enabled 是否允许点击
*/ */
public void setServiceSwitchEnabled(boolean enabled) { public void setServiceSwitchEnabled(boolean enabled) {
@@ -537,9 +549,9 @@ public class MainContentView {
LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用"); LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用");
return; return;
} }
// 基础校验:对话框/上下文为空 // 基础校验:对话框/上下文/Builder 为空
if (mConfigConfirmDialog == null || mContext == null) { if (mDialogBuilder == null || mContext == null) {
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框/上下文异常,无法显示"); LogUtils.e(TAG, "showConfigConfirmDialog: 对话框Builder/上下文异常,无法显示");
if (mTempConfigData != null) cancelConfigChange(); if (mTempConfigData != null) cancelConfigChange();
return; return;
} }
@@ -550,20 +562,20 @@ public class MainContentView {
if (mTempConfigData != null) cancelConfigChange(); if (mTempConfigData != null) cancelConfigChange();
return; return;
} }
// 重新构建对话框(核心:确保最新消息生效)
mConfigConfirmDialog = mDialogBuilder.create();
// 显示对话框,设置状态锁+关闭监听 // 显示对话框,设置状态锁+关闭监听
if (!mConfigConfirmDialog.isShowing()) { mConfigConfirmDialog.show();
isDialogShowing = true; isDialogShowing = true;
mConfigConfirmDialog.show(); // 对话框关闭时解锁
// 对话框关闭时解锁(无论确认/取消/外部点击,均解锁) mConfigConfirmDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
mConfigConfirmDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override
@Override public void onDismiss(DialogInterface dialog) {
public void onDismiss(DialogInterface dialog) { isDialogShowing = false;
isDialogShowing = false; mConfigConfirmDialog.setOnDismissListener(null);
mConfigConfirmDialog.setOnDismissListener(null); // 移除监听,避免内存泄漏 }
} });
}); LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
}
} }
/** /**
@@ -576,36 +588,36 @@ public class MainContentView {
} }
switch (mTempConfigData.changeType) { switch (mTempConfigData.changeType) {
// 充电提醒开关(适配 AppConfigUtils 无 Activity 参数调用) // 充电提醒开关
case CHANGE_TYPE_CHARGE_SWITCH: case CHANGE_TYPE_CHARGE_SWITCH:
mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue); mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认,值=" + mTempConfigData.newBooleanValue); LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
break; break;
// 耗电提醒开关(适配 AppConfigUtils 无 Activity 参数调用) // 耗电提醒开关
case CHANGE_TYPE_USAGE_SWITCH: case CHANGE_TYPE_USAGE_SWITCH:
mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue); mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认,值=" + mTempConfigData.newBooleanValue); LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
break; break;
// 服务总开关(核心优化同步更新服务控制Bean而非AppConfig // 服务总开关(核心:持久化配置+触发 Activity 回调
case CHANGE_TYPE_SERVICE_SWITCH: case CHANGE_TYPE_SERVICE_SWITCH:
// 1. 保存服务控制配置到本地(持久化自启动状态) // 1. 保存服务控制配置到本地
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class); ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
if (serviceBean == null) serviceBean = new ControlCenterServiceBean(false); if (serviceBean == null) serviceBean = new ControlCenterServiceBean(false);
serviceBean.setIsEnableService(mTempConfigData.newBooleanValue); serviceBean.setIsEnableService(mTempConfigData.newBooleanValue);
ControlCenterService.updateServiceControlConfig(mContext, serviceBean); ControlCenterService.updateServiceControlConfig(mContext, serviceBean);
// 2. 回调 Activity,触发服务启停 // 2. 强制触发 Activity 回调,执行服务启停逻辑
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue + ",已持久化配置"); LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
break; break;
// 充电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用) // 充电提醒进度条
case CHANGE_TYPE_CHARGE_SEEKBAR: case CHANGE_TYPE_CHARGE_SEEKBAR:
mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue); mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue);
mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue); mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认,值=" + mTempConfigData.newIntValue); LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认,值=" + mTempConfigData.newIntValue);
break; break;
// 耗电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用) // 耗电提醒进度条
case CHANGE_TYPE_USAGE_SEEKBAR: case CHANGE_TYPE_USAGE_SEEKBAR:
mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue); mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue);
mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue); mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue);
@@ -630,28 +642,24 @@ public class MainContentView {
} }
switch (mTempConfigData.changeType) { switch (mTempConfigData.changeType) {
// 充电提醒开关:恢复原始状态
case CHANGE_TYPE_CHARGE_SWITCH: case CHANGE_TYPE_CHARGE_SWITCH:
if (cbEnableChargeReminder != null) { if (cbEnableChargeReminder != null) {
cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue); cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
// 耗电提醒开关:恢复原始状态
case CHANGE_TYPE_USAGE_SWITCH: case CHANGE_TYPE_USAGE_SWITCH:
if (cbEnableUsageReminder != null) { if (cbEnableUsageReminder != null) {
cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue); cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
// 服务总开关恢复原始状态核心优化从服务控制Bean读取原始值
case CHANGE_TYPE_SERVICE_SWITCH: case CHANGE_TYPE_SERVICE_SWITCH:
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setChecked(mTempConfigData.originalBooleanValue); swEnableService.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 服务开关取消,恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "cancelConfigChange: 服务开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
// 充电提醒进度条:恢复原始进度+更新视图
case CHANGE_TYPE_CHARGE_SEEKBAR: case CHANGE_TYPE_CHARGE_SEEKBAR:
if (sbChargeReminder != null) { if (sbChargeReminder != null) {
sbChargeReminder.setProgress(mTempConfigData.originalIntValue); sbChargeReminder.setProgress(mTempConfigData.originalIntValue);
@@ -663,7 +671,6 @@ public class MainContentView {
} }
LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消,恢复值=" + mTempConfigData.originalIntValue); LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消,恢复值=" + mTempConfigData.originalIntValue);
break; break;
// 耗电提醒进度条:恢复原始进度+更新视图
case CHANGE_TYPE_USAGE_SEEKBAR: case CHANGE_TYPE_USAGE_SEEKBAR:
if (sbUsageReminder != null) { if (sbUsageReminder != null) {
sbUsageReminder.setProgress(mTempConfigData.originalIntValue); sbUsageReminder.setProgress(mTempConfigData.originalIntValue);
@@ -705,7 +712,7 @@ public class MainContentView {
} }
/** /**
* 新增:获取服务启用状态统一从服务控制Bean读取确保全链路状态一致 * 获取服务启用状态统一从服务控制Bean读取确保全链路状态一致
* @return 服务启用状态true=启用false=禁用) * @return 服务启用状态true=启用false=禁用)
*/ */
private boolean getServiceEnableState() { private boolean getServiceEnableState() {
@@ -715,17 +722,22 @@ public class MainContentView {
} }
/** /**
* 新增:根据变更类型更新对话框提示语(差异化提示,提升用户体验 * 根据变更类型更新对话框提示语(核心优化:通过 Builder 更新,确保生效
*/ */
private void updateDialogMessageByChangeType() { private void updateDialogMessageByChangeType() {
if (mConfigConfirmDialog == null || mTempConfigData == null) return; if (mDialogBuilder == null || mTempConfigData == null) return;
String message; String message;
if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) { if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) {
message = mTempConfigData.newBooleanValue ? "启用服务后,将后台持续监控电池状态,是否确认?" : "禁用服务后,电池监控功能将停止,是否确认?"; // 服务开关差异化提示语
message = mTempConfigData.newBooleanValue ?
"启用服务后,将后台持续监控电池状态,是否确认?" :
"禁用服务后,电池监控功能将停止,是否确认?";
} else { } else {
// 普通配置默认提示语
message = "是否确认修改当前配置?"; message = "是否确认修改当前配置?";
} }
mConfigConfirmDialog.setMessage(message); // 通过 Builder 设置消息,确保弹窗显示最新内容
mDialogBuilder.setMessage(message);
} }
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)======================== // ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================