服务启停调试中。。。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#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
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.9
|
||||
buildCount=18
|
||||
buildCount=25
|
||||
baseBetaVersion=15.14.10
|
||||
|
||||
@@ -45,6 +45,7 @@ import cc.winboll.studio.powerbell.views.MainContentView;
|
||||
* @Date 2025/12/17 13:14
|
||||
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
|
||||
* 适配:Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
|
||||
* 核心规则:UI开关仅管理本地配置,服务启停仅在应用启动时根据配置执行
|
||||
*/
|
||||
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_LOAD_BACKGROUND = 2; // 加载背景
|
||||
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 Handler sGlobalHandler; // 全局Handler(统一消息分发,避免多Handler混乱)
|
||||
private static MainActivity sMainActivity; // 全局Activity实例(销毁时必须置空)
|
||||
private static Handler sGlobalHandler; // 全局Handler(统一消息分发)
|
||||
|
||||
// ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减)========================
|
||||
// 工具类实例(单例,避免重复初始化)
|
||||
@@ -71,15 +72,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
private BackgroundSourceUtils mBgSourceUtils;
|
||||
// 应用核心实例
|
||||
private App mApplication;
|
||||
private MainContentView mMainContentView; // 核心视图封装类(统一管理视图)
|
||||
private MainContentView mMainContentView; // 核心视图封装类
|
||||
// 基础视图组件
|
||||
private Toolbar mToolbar;
|
||||
private ViewStub mAdsViewStub;
|
||||
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
|
||||
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
|
||||
// 资源与菜单
|
||||
private Menu mMenu;
|
||||
private Drawable mFrameDrawable; // 框架背景资源(适配API30主题)
|
||||
// 新增:服务控制核心Bean(本地持久化,管理服务自启动状态)
|
||||
private Drawable mFrameDrawable; // 框架背景资源
|
||||
// 服务控制核心Bean
|
||||
private ControlCenterServiceBean mServiceControlBean;
|
||||
|
||||
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
|
||||
@@ -97,15 +98,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
LogUtils.d(TAG, "onCreate: 进入");
|
||||
super.onCreate(savedInstanceState);
|
||||
// 1. 初始化全局核心组件(Handler优先,避免消息丢失)
|
||||
// 1. 初始化全局Handler(优先初始化,避免消息丢失)
|
||||
initGlobalHandler();
|
||||
// 2. 加载布局+初始化核心流程
|
||||
setContentView(R.layout.activity_main);
|
||||
initPermissionUtils(); // 权限工具类(提前初始化,保障权限请求时效)
|
||||
initMainContentView(); // 核心视图封装(替代原ViewHolder)
|
||||
initCriticalView(); // 首屏核心视图(Toolbar等,保障首屏加载速度)
|
||||
initCoreUtilsAsync(); // 异步初始化工具类(避免主线程阻塞)
|
||||
loadNonCriticalViewDelayed(); // 延迟加载非核心视图(广告,不影响首屏体验)
|
||||
initPermissionUtils();
|
||||
initMainContentView();
|
||||
initCriticalView();
|
||||
initCoreUtilsAsync();
|
||||
loadNonCriticalViewDelayed();
|
||||
LogUtils.d(TAG, "onCreate: 退出");
|
||||
}
|
||||
|
||||
@@ -113,7 +114,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
LogUtils.d(TAG, "onPostCreate: 进入");
|
||||
super.onPostCreate(savedInstanceState);
|
||||
// 视图初始化完成后请求权限(避免视图未就绪导致的异常)
|
||||
mPermissionUtils.startPermissionRequest(this);
|
||||
LogUtils.d(TAG, "onPostCreate: 退出");
|
||||
}
|
||||
@@ -122,19 +122,17 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onResume() {
|
||||
LogUtils.d(TAG, "onResume: 进入");
|
||||
super.onResume();
|
||||
// 1. 恢复背景(适配后台切前台场景,小米手机保活优化)
|
||||
// 恢复背景+同步服务开关UI(仅本地配置)
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||
LogUtils.d(TAG, "onResume: 发送加载背景消息");
|
||||
// 新增:恢复时同步服务开关UI(避免开关状态与实际服务状态不一致)
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
LogUtils.d(TAG, "onResume: 发送背景加载+服务开关更新消息");
|
||||
}
|
||||
// 2. 恢复广告(非核心,容错处理)
|
||||
// 恢复广告
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.resumeADs(this);
|
||||
LogUtils.d(TAG, "onResume: 恢复广告展示");
|
||||
}
|
||||
// 3. 关键调整:应用切前台,设置RemindThread为前台状态(开启提醒)
|
||||
// 设置RemindThread前台状态
|
||||
setRemindThreadForeground(true);
|
||||
LogUtils.d(TAG, "onResume: 退出");
|
||||
}
|
||||
@@ -143,7 +141,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onPause() {
|
||||
LogUtils.d(TAG, "onPause: 进入");
|
||||
super.onPause();
|
||||
// 关键调整:应用切后台,设置RemindThread为后台状态(停止提醒+重置无效电量)
|
||||
// 设置RemindThread后台状态
|
||||
setRemindThreadForeground(false);
|
||||
LogUtils.d(TAG, "onPause: 退出");
|
||||
}
|
||||
@@ -152,40 +150,33 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onDestroy() {
|
||||
LogUtils.d(TAG, "onDestroy: 进入");
|
||||
super.onDestroy();
|
||||
// 1. 释放广告资源(避免内存泄漏,适配API30资源管控)
|
||||
// 1. 释放广告资源
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.releaseAdResources();
|
||||
mADsBannerView = null;
|
||||
LogUtils.d(TAG, "onDestroy: 释放广告资源完成");
|
||||
}
|
||||
// 2. 释放核心视图资源(调用封装类释放方法,彻底断开引用)
|
||||
// 2. 释放核心视图资源
|
||||
if (mMainContentView != null) {
|
||||
mMainContentView.releaseResources();
|
||||
mMainContentView = null;
|
||||
LogUtils.d(TAG, "onDestroy: 释放核心视图资源完成");
|
||||
}
|
||||
// 3. 关键调整:Activity销毁,强制销毁RemindThread单例(彻底停止线程)
|
||||
// 3. 销毁线程+清理Handler
|
||||
RemindThread.destroyInstance();
|
||||
LogUtils.d(TAG, "onDestroy: 强制销毁RemindThread单例完成");
|
||||
// 4. 置空全局实例(杜绝内存泄漏,必须执行)
|
||||
sMainActivity = null;
|
||||
// 5. 清理Handler(移除所有消息,避免Activity销毁后回调)
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.removeCallbacksAndMessages(null);
|
||||
sGlobalHandler = null;
|
||||
LogUtils.d(TAG, "onDestroy: 清理全局Handler完成");
|
||||
}
|
||||
// 6. 释放Drawable资源(断开回调,辅助GC回收)
|
||||
// 4. 释放Drawable+置空全局实例
|
||||
if (mFrameDrawable != null) {
|
||||
mFrameDrawable.setCallback(null);
|
||||
mFrameDrawable = null;
|
||||
LogUtils.d(TAG, "onDestroy: 释放Drawable资源完成");
|
||||
}
|
||||
// 7. 置空所有辅助实例(辅助GC,避免残留引用)
|
||||
sMainActivity = null;
|
||||
// 5. 置空所有辅助实例
|
||||
mPermissionUtils = null;
|
||||
mAppConfigUtils = null;
|
||||
mBgSourceUtils = null;
|
||||
mServiceControlBean = null; // 新增:置空服务控制Bean
|
||||
mServiceControlBean = null;
|
||||
mMenu = null;
|
||||
mApplication = null;
|
||||
mToolbar = null;
|
||||
@@ -197,32 +188,26 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
LogUtils.d(TAG, "onActivityResult: 进入,requestCode=" + requestCode + ",resultCode=" + resultCode);
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
// 1. 权限请求结果处理
|
||||
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
|
||||
// 2. 背景设置完成后重新加载背景
|
||||
// 背景设置完成后重新加载背景
|
||||
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送加载背景消息");
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "onActivityResult: 退出");
|
||||
}
|
||||
|
||||
// ======================== 菜单与导航方法(统一归类,用户交互入口)========================
|
||||
// ======================== 菜单与导航方法 ========================
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
LogUtils.d(TAG, "onCreateOptionsMenu: 进入");
|
||||
mMenu = menu;
|
||||
// 1. 加载主题菜单
|
||||
AESThemeUtil.inflateMenu(this, menu);
|
||||
// 2. 调试模式加载开发菜单+单元测试菜单
|
||||
if (App.isDebugging()) {
|
||||
DevelopUtils.inflateMenu(this, menu);
|
||||
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
|
||||
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载开发/单元测试菜单");
|
||||
}
|
||||
// 3. 加载主菜单
|
||||
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
|
||||
LogUtils.d(TAG, "onCreateOptionsMenu: 退出");
|
||||
return true;
|
||||
@@ -231,18 +216,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
LogUtils.d(TAG, "onOptionsItemSelected: 进入,itemId=" + item.getItemId());
|
||||
// 1. 主题切换处理(切换后重建Activity生效)
|
||||
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
|
||||
recreate();
|
||||
LogUtils.d(TAG, "onOptionsItemSelected: 主题切换,重建Activity");
|
||||
return true;
|
||||
}
|
||||
// 2. 开发模式菜单处理
|
||||
if (DevelopUtils.onDevelopItemSelected(this, item)) {
|
||||
LogUtils.d(TAG, "onOptionsItemSelected: 开发菜单操作完成");
|
||||
return true;
|
||||
}
|
||||
// 3. 主菜单逻辑分发(按功能分类,清晰易维护)
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
@@ -272,31 +252,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void setupToolbar() {
|
||||
super.setupToolbar();
|
||||
// 主页面隐藏返回按钮(符合用户操作习惯)
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
LogUtils.d(TAG, "setupToolbar: 隐藏Toolbar返回按钮");
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 页面交互方法(用户操作响应,统一归类)========================
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// 退到后台,不销毁Activity(提升用户体验,小米手机后台保活优化)
|
||||
moveTaskToBack(true);
|
||||
LogUtils.d(TAG, "onBackPressed: 应用退到后台");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
// 保留系统默认按键分发逻辑,无自定义需求
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
// ======================== 核心初始化方法(按优先级排序,核心优先加载)========================
|
||||
/**
|
||||
* 初始化权限工具类(提前初始化,保障权限请求无延迟)
|
||||
*/
|
||||
// ======================== 核心初始化方法 ========================
|
||||
private void initPermissionUtils() {
|
||||
LogUtils.d(TAG, "initPermissionUtils: 进入");
|
||||
mPermissionUtils = PermissionUtils.getInstance();
|
||||
@@ -304,7 +276,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化全局Handler(统一消息分发,Java7显式实现,避免内存泄漏)
|
||||
* 初始化全局Handler(核心优化:弱引用+生命周期校验,杜绝内存泄漏)
|
||||
*/
|
||||
private void initGlobalHandler() {
|
||||
LogUtils.d(TAG, "initGlobalHandler: 进入");
|
||||
@@ -312,19 +284,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
sGlobalHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
LogUtils.d(TAG, "handleMessage: 接收消息,what=" + msg.what);
|
||||
// 消息处理前先校验Activity状态(避免销毁后操作UI)
|
||||
if (sMainActivity == null || sMainActivity.isFinishing()) {
|
||||
// 严格校验Activity状态,避免销毁后操作UI
|
||||
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
|
||||
LogUtils.w(TAG, "handleMessage: Activity已销毁,跳过消息处理");
|
||||
return;
|
||||
}
|
||||
// 按消息类型分发逻辑
|
||||
LogUtils.d(TAG, "handleMessage: 接收消息,what=" + msg.what);
|
||||
switch (msg.what) {
|
||||
case MSG_RELOAD_APPCONFIG:
|
||||
sMainActivity.updateViewData();
|
||||
break;
|
||||
case MSG_CURRENTVALUEBATTERY:
|
||||
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
|
||||
if (sMainActivity.mMainContentView != null) {
|
||||
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
|
||||
}
|
||||
break;
|
||||
case MSG_LOAD_BACKGROUND:
|
||||
sMainActivity.reloadBackground();
|
||||
@@ -334,7 +307,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
AppConfigBean configBean = (AppConfigBean) msg.obj;
|
||||
sMainActivity.restartRemindThread(configBean);
|
||||
break;
|
||||
// 新增:更新服务开关UI(同步实际服务状态,避免开关与服务状态不一致)
|
||||
case MSG_UPDATE_SERVICE_SWITCH:
|
||||
sMainActivity.updateServiceSwitchUI();
|
||||
break;
|
||||
@@ -347,9 +319,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "initGlobalHandler: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化核心视图封装类(统一管理视图,替代原ViewHolder模式)
|
||||
*/
|
||||
private void initMainContentView() {
|
||||
LogUtils.d(TAG, "initMainContentView: 进入");
|
||||
View rootView = findViewById(android.R.id.content);
|
||||
@@ -358,26 +327,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "initMainContentView: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化首屏核心视图(Toolbar等,保障首屏加载速度,优先渲染)
|
||||
*/
|
||||
private void initCriticalView() {
|
||||
LogUtils.d(TAG, "initCriticalView: 进入");
|
||||
sMainActivity = this; // 赋值全局实例(用于Handler回调)
|
||||
// 初始化Toolbar
|
||||
sMainActivity = this;
|
||||
mToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(mToolbar);
|
||||
if (mToolbar != null) {
|
||||
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
|
||||
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
|
||||
}
|
||||
// 初始化广告ViewStub(仅初始化Stub,不立即加载广告)
|
||||
mAdsViewStub = findViewById(R.id.stub_ads_banner);
|
||||
LogUtils.d(TAG, "initCriticalView: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步初始化核心工具类(子线程执行,避免主线程阻塞,提升首屏加载速度)
|
||||
* 异步初始化核心工具类(保留服务启停逻辑:应用启动时根据配置执行)
|
||||
*/
|
||||
private void initCoreUtilsAsync() {
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 进入");
|
||||
@@ -385,41 +348,59 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
|
||||
// 子线程初始化工具类(无UI操作,安全执行)
|
||||
mApplication = (App) getApplication();
|
||||
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
|
||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
|
||||
// 新增:初始化服务控制Bean(读取本地持久化状态,管理自启动)
|
||||
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
|
||||
if (mServiceControlBean == null) {
|
||||
// 本地无配置,默认禁用服务(与服务初始化逻辑一致)
|
||||
mServiceControlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无服务控制配置,创建默认禁用配置");
|
||||
}
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 核心工具类+服务控制Bean初始化完成");
|
||||
|
||||
// 切换主线程更新UI(Java7显式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() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 切换主线程更新UI");
|
||||
if (isFinishing()) {
|
||||
if (isFinishing() || isDestroyed()) {
|
||||
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁,跳过UI更新");
|
||||
return;
|
||||
}
|
||||
// 适配API30加载Drawable(添加主题参数,避免系统警告)
|
||||
// 适配API30+主题加载Drawable
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
|
||||
} else {
|
||||
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame);
|
||||
}
|
||||
// 初始化完成后执行核心业务
|
||||
updateViewData(); // 更新视图数据
|
||||
checkServiceAsync(); // 异步检查服务状态
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); // 加载背景
|
||||
// 新增:初始化服务开关UI(确保开关状态与本地配置一致)
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
// 执行核心业务
|
||||
updateViewData();
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
|
||||
@@ -428,49 +409,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟加载非核心视图(广告,延迟500ms加载,不影响首屏体验)
|
||||
*/
|
||||
private void loadNonCriticalViewDelayed() {
|
||||
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入");
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isFinishing()) {
|
||||
LogUtils.w(TAG, "loadNonCriticalViewDelayed: Activity已销毁,跳过广告加载");
|
||||
if (isFinishing() || isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
loadAdsView(); // 加载广告视图
|
||||
loadAdsView();
|
||||
}
|
||||
}, DELAY_LOAD_NON_CRITICAL);
|
||||
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出");
|
||||
}
|
||||
|
||||
// ======================== 视图操作方法(UI更新,统一归类)========================
|
||||
/**
|
||||
* 加载广告视图(非核心,容错处理,避免广告加载失败影响主功能)
|
||||
*/
|
||||
// ======================== 视图操作方法 ========================
|
||||
private void loadAdsView() {
|
||||
LogUtils.d(TAG, "loadAdsView: 进入");
|
||||
if (mAdsViewStub == null) {
|
||||
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空,加载失败");
|
||||
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空");
|
||||
return;
|
||||
}
|
||||
if (mADsBannerView == null) {
|
||||
View adsView = mAdsViewStub.inflate();
|
||||
mADsBannerView = adsView.findViewById(R.id.adsbanner);
|
||||
LogUtils.d(TAG, "loadAdsView: 广告视图加载完成");
|
||||
}
|
||||
LogUtils.d(TAG, "loadAdsView: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新视图数据(调用核心视图封装类方法,统一更新UI)
|
||||
*/
|
||||
private void updateViewData() {
|
||||
LogUtils.d(TAG, "updateViewData: 进入");
|
||||
if (mMainContentView == null || mFrameDrawable == null) {
|
||||
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空,跳过更新");
|
||||
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空");
|
||||
return;
|
||||
}
|
||||
mMainContentView.updateViewData(mFrameDrawable);
|
||||
@@ -478,234 +448,145 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "updateViewData: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载背景(适配背景切换,小米手机图片加载优化,容错处理)
|
||||
*/
|
||||
private void reloadBackground() {
|
||||
LogUtils.d(TAG, "reloadBackground: 进入");
|
||||
if (mMainContentView == null || mBgSourceUtils == null) {
|
||||
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空,跳过加载");
|
||||
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空");
|
||||
return;
|
||||
}
|
||||
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||
if (currentBgBean != null) {
|
||||
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
|
||||
LogUtils.d(TAG, "reloadBackground: 加载自定义背景完成");
|
||||
} else {
|
||||
LogUtils.e(TAG, "reloadBackground: 无自定义背景,加载默认背景");
|
||||
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
|
||||
}
|
||||
LogUtils.d(TAG, "reloadBackground: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主布局背景颜色(适配背景配置,API30安全防护)
|
||||
*/
|
||||
private void setMainLayoutBackgroundColor() {
|
||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入");
|
||||
if (isFinishing() || mMainContentView == null || mBgSourceUtils == null) {
|
||||
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效,跳过设置");
|
||||
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
|
||||
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效");
|
||||
return;
|
||||
}
|
||||
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||
if (currentBgBean != null) {
|
||||
int bgColor = currentBgBean.getPixelColor();
|
||||
mMainContentView.mainLayout.setBackgroundColor(bgColor);
|
||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局颜色设置完成");
|
||||
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
|
||||
}
|
||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:更新服务开关UI(同步「本地配置+实际服务状态」,避免开关与服务状态不一致)
|
||||
* 更新服务开关UI(仅同步本地配置,不校验服务状态)
|
||||
*/
|
||||
private void updateServiceSwitchUI() {
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 进入");
|
||||
if (mMainContentView == null || mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空,跳过更新");
|
||||
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空");
|
||||
return;
|
||||
}
|
||||
// 开关状态 = 本地服务控制配置启用状态(自启动状态)
|
||||
boolean isServiceEnabled = mServiceControlBean.isEnableService();
|
||||
// 禁用开关点击(避免更新UI时触发重复回调)
|
||||
// 仅读取本地配置状态,不涉及服务状态校验
|
||||
boolean configEnabled = mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 本地配置状态=" + configEnabled);
|
||||
|
||||
// 仅更新UI开关状态
|
||||
mMainContentView.setServiceSwitchEnabled(false);
|
||||
// 更新开关状态
|
||||
mMainContentView.setServiceSwitchChecked(isServiceEnabled);
|
||||
// 启用开关点击
|
||||
mMainContentView.setServiceSwitchChecked(configEnabled);
|
||||
mMainContentView.setServiceSwitchEnabled(true);
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI更新完成,当前状态=" + isServiceEnabled);
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 退出");
|
||||
}
|
||||
|
||||
// ======================== 服务与线程管理方法(业务核心,统一归类)========================
|
||||
// ======================== 服务与线程管理方法 ========================
|
||||
/**
|
||||
* 异步检查服务状态(子线程执行,避免主线程阻塞,适配API30前台服务规范)
|
||||
*/
|
||||
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服务规范)
|
||||
* 重启提醒线程(仅由配置变更触发,不与UI开关联动)
|
||||
*/
|
||||
private void restartRemindThread(AppConfigBean configBean) {
|
||||
LogUtils.d(TAG, "restartRemindThread: 进入");
|
||||
if (configBean == null || mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "restartRemindThread: 配置为空/服务控制Bean为空,跳过重启");
|
||||
LogUtils.e(TAG, "restartRemindThread: 配置/服务控制Bean为空");
|
||||
return;
|
||||
}
|
||||
// 服务未启用时,不重启线程(直接返回)
|
||||
if (!mServiceControlBean.isEnableService()) {
|
||||
LogUtils.w(TAG, "restartRemindThread: 服务已禁用,跳过线程重启");
|
||||
return;
|
||||
}
|
||||
// 服务未运行时,先启动服务
|
||||
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
|
||||
ControlCenterService.startControlCenterService(this);
|
||||
LogUtils.d(TAG, "restartRemindThread: 服务未运行,先启动服务");
|
||||
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
|
||||
ControlCenterService.startControlCenterService(getApplicationContext());
|
||||
}
|
||||
// 关键优化:重启前先销毁旧线程,避免线程复用导致的状态脏数据
|
||||
RemindThread.destroyInstance();
|
||||
LogUtils.d(TAG, "restartRemindThread: 销毁旧线程完成,准备启动新线程");
|
||||
|
||||
// 发送重启指令到服务(通过Intent传递最新配置)
|
||||
ControlCenterService.updateStatus(this, configBean);
|
||||
LogUtils.d(TAG, "restartRemindThread: 发送线程重启指令到服务完成");
|
||||
ControlCenterService.updateStatus(getApplicationContext(), configBean);
|
||||
LogUtils.d(TAG, "restartRemindThread: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键新增:设置RemindThread前台/后台状态(核心修复无限提醒问题)
|
||||
* @param isForeground true=前台(开启提醒),false=后台(停止提醒)
|
||||
* 设置线程前后台状态(依赖服务运行状态)
|
||||
*/
|
||||
private void setRemindThreadForeground(boolean isForeground) {
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: 进入,前台状态=" + isForeground);
|
||||
// 服务未运行时,跳过状态设置(线程未启动)
|
||||
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
|
||||
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
|
||||
LogUtils.w(TAG, "setRemindThreadForeground: 服务未运行,跳过状态设置");
|
||||
return;
|
||||
}
|
||||
// 调用RemindThread新增方法,设置前台状态(线程安全)
|
||||
try {
|
||||
RemindThread.getInstance(this, null).setAppForeground(isForeground);
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: RemindThread状态设置完成");
|
||||
RemindThread.getInstance(getApplicationContext(), null).setAppForeground(isForeground);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 首次启动时Handler可能未就绪,容错处理(服务会后续同步状态)
|
||||
LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化完成,后续服务会同步状态", e);
|
||||
LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化", e);
|
||||
}
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:切换服务启用/禁用状态(核心修复:持久化配置+启停服务+更新UI+重启线程)
|
||||
* @param isEnable true=启用服务(自启动+启动服务),false=禁用服务(停止服务)
|
||||
* 切换服务启用状态(仅持久化本地配置,点击UI开关时不联动服务启停)
|
||||
*/
|
||||
private void toggleServiceEnableState(boolean isEnable) {
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable);
|
||||
if (mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空,切换失败");
|
||||
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空");
|
||||
return;
|
||||
}
|
||||
// 1. 更新本地服务控制配置(持久化,实现自启动)
|
||||
// 仅更新本地配置并持久化
|
||||
mServiceControlBean.setIsEnableService(isEnable);
|
||||
ControlCenterService.updateServiceControlConfig(this, mServiceControlBean);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务控制配置已持久化,自启动状态=" + isEnable);
|
||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 本地服务控制配置已持久化,状态=" + isEnable);
|
||||
|
||||
// 2. 启停服务(通过服务静态方法,适配API30前台服务规范)
|
||||
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(确保开关状态与实际服务状态一致)
|
||||
// 仅更新UI,无服务启停操作
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务状态切换完成");
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 退出");
|
||||
}
|
||||
|
||||
// ======================== 页面跳转方法(封装逻辑,减少冗余)========================
|
||||
/**
|
||||
* 启动关于页面(封装跳转逻辑,统一参数传递,便于维护)
|
||||
*/
|
||||
// ======================== 页面跳转方法 ========================
|
||||
private void startAboutActivity() {
|
||||
LogUtils.d(TAG, "startAboutActivity: 进入");
|
||||
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
|
||||
APPInfo appInfo = genDefaultAppInfo();
|
||||
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
|
||||
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
|
||||
LogUtils.d(TAG, "startAboutActivity: 启动关于页面完成");
|
||||
LogUtils.d(TAG, "startAboutActivity: 退出");
|
||||
}
|
||||
|
||||
// ======================== 消息发送方法(统一封装,避免冗余,保障消息安全)========================
|
||||
/**
|
||||
* 发送重启RemindThread线程消息(携带最新配置,确保线程使用最新参数)
|
||||
*/
|
||||
// ======================== 消息发送方法 ========================
|
||||
private void sendRestartRemindThreadMessage() {
|
||||
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入");
|
||||
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
|
||||
LogUtils.e(TAG, "sendRestartRemindThreadMessage: Handler/配置为空,跳过发送");
|
||||
LogUtils.e(TAG, "sendRestartRemindThreadMessage: 环境无效");
|
||||
return;
|
||||
}
|
||||
// 复用Message,避免内存抖动(优化性能)
|
||||
Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD);
|
||||
msg.obj = mAppConfigUtils.mAppConfigBean;
|
||||
sGlobalHandler.sendMessage(msg);
|
||||
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 发送线程重启消息完成");
|
||||
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出");
|
||||
}
|
||||
|
||||
// ======================== 静态工具方法(全局调用,统一入口)========================
|
||||
/**
|
||||
* 重新加载应用配置(全局调用,触发视图更新)
|
||||
*/
|
||||
// ======================== 静态工具方法 ========================
|
||||
public static void reloadAppConfig() {
|
||||
LogUtils.d(TAG, "reloadAppConfig: 发送重新加载配置消息");
|
||||
LogUtils.d(TAG, "reloadAppConfig: 发送配置更新消息");
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送当前电量更新消息(全局调用,实时更新UI)
|
||||
*/
|
||||
public static void sendCurrentBatteryValueMessage(int value) {
|
||||
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value + ",发送更新消息");
|
||||
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value);
|
||||
if (sGlobalHandler != null) {
|
||||
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
|
||||
msg.arg1 = value;
|
||||
@@ -713,14 +594,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 辅助工具方法(封装重复逻辑,提升复用性)========================
|
||||
/**
|
||||
* 从URI获取图片真实路径(适配API30媒体存储权限,Java7显式Cursor操作,避免资源泄漏)
|
||||
*/
|
||||
// ======================== 辅助工具方法 ========================
|
||||
private String getRealPathFromUri(Uri contentUri) {
|
||||
LogUtils.d(TAG, "getRealPathFromUri: 进入");
|
||||
if (contentUri == null) {
|
||||
LogUtils.e(TAG, "getRealPathFromUri: URI为空,获取失败");
|
||||
LogUtils.e(TAG, "getRealPathFromUri: URI为空");
|
||||
return null;
|
||||
}
|
||||
String realPath = null;
|
||||
@@ -732,24 +610,16 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
|
||||
if (columnIndex > -1) {
|
||||
realPath = cursor.getString(columnIndex);
|
||||
LogUtils.d(TAG, "getRealPathFromUri: 获取图片路径=" + realPath);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Java7必须显式关闭Cursor,避免资源泄漏(无try-with-resources语法)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
if (realPath == null) {
|
||||
LogUtils.e(TAG, "getRealPathFromUri: 获取图片路径失败");
|
||||
}
|
||||
LogUtils.d(TAG, "getRealPathFromUri: 退出");
|
||||
LogUtils.d(TAG, "getRealPathFromUri: 退出,路径=" + realPath);
|
||||
return realPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成默认应用信息(关于页面使用,封装参数赋值,便于维护)
|
||||
*/
|
||||
private APPInfo genDefaultAppInfo() {
|
||||
LogUtils.d(TAG, "genDefaultAppInfo: 进入");
|
||||
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.setAppAPKName("PowerBell");
|
||||
appInfo.setAppAPKFolderName("PowerBell");
|
||||
LogUtils.d(TAG, "genDefaultAppInfo: 生成应用信息完成");
|
||||
LogUtils.d(TAG, "genDefaultAppInfo: 退出");
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
// ======================== MainContentView 事件回调实现(视图事件触发业务逻辑)========================
|
||||
// ======================== MainContentView 事件回调 ========================
|
||||
@Override
|
||||
public void onChargeReminderSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 状态=" + isChecked);
|
||||
@@ -785,7 +654,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void onServiceSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
|
||||
// 核心修复:点击服务开关,触发「配置持久化+服务启停+UI更新」全链路逻辑
|
||||
// 仅更新本地配置,不触发服务启停
|
||||
toggleServiceEnableState(isChecked);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cc.winboll.studio.powerbell.services;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -10,24 +11,26 @@ import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/17 15:48
|
||||
* @Describe 电池提醒核心服务:通过本地持久化 ControlCenterServiceBean 控制自启动,统一管理线程、通知、配置,适配Java7+API30
|
||||
* @Describe 电池提醒核心服务:修复前台服务超时异常,优先在onCreate发送通知,适配Java7+API36
|
||||
*/
|
||||
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 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 final Object mServiceLock = new Object(); // 全局并发锁
|
||||
|
||||
// ================================== 服务生命周期方法(onCreate→onStartCommand→onDestroy)=================================
|
||||
// ================================== 服务生命周期方法(核心修复:onCreate优先发送通知)=================================
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@@ -60,7 +63,11 @@ public class ControlCenterService extends Service {
|
||||
synchronized (mServiceLock) {
|
||||
isServiceRunning = true;
|
||||
mIsDestroyed = false;
|
||||
// 初始化服务控制配置:优先读取本地持久化配置,无则创建默认禁用配置
|
||||
|
||||
// ================================== 【修复点1:最优先执行前台通知发送】=================================
|
||||
initForegroundNotificationImmediately();
|
||||
|
||||
// 原有逻辑:读取本地服务控制配置
|
||||
mServiceControlBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
|
||||
if (mServiceControlBean == null) {
|
||||
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() ? "启用" : "禁用"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,9 +89,9 @@ public class ControlCenterService extends Service {
|
||||
synchronized (mServiceLock) {
|
||||
if (mServiceControlBean.isEnableService()) {
|
||||
LogUtils.d(TAG, "onStartCommand: 服务已启用,执行核心逻辑");
|
||||
// 启用状态:处理指令+绑定前台通知+启动业务,返回START_STICKY(回收后重启)
|
||||
// 启用状态:处理指令+启动业务,返回START_STICKY(回收后重启)
|
||||
handleExternalCommand(intent);
|
||||
rebindForegroundNotify();
|
||||
// ================================== 【修复点2:删除rebindForegroundNotify(),避免重复调用】=================================
|
||||
initServiceBusinessIfNeed(); // 按需初始化业务(避免重复初始化)
|
||||
// 新增:业务初始化完成后,同步应用前台状态到线程(防止状态丢失)
|
||||
syncAppForegroundStateToThread();
|
||||
@@ -123,6 +130,54 @@ public class ControlCenterService extends Service {
|
||||
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传递)=================================
|
||||
/**
|
||||
* 读取本地最新服务控制配置(实时同步,确保与用户设置一致)
|
||||
@@ -203,6 +258,7 @@ public class ControlCenterService extends Service {
|
||||
// ================================== 核心业务初始化方法(按依赖顺序排列)=================================
|
||||
/**
|
||||
* 初始化通知管理工具类,构建前台保活通知模型
|
||||
* 【修复点3:移除内部的startForegroundNotifyImmediately()调用,避免重复发送】
|
||||
*/
|
||||
private void initNotificationManager() {
|
||||
LogUtils.d(TAG, "initNotificationManager: 初始化通知工具类");
|
||||
@@ -215,8 +271,7 @@ public class ControlCenterService extends Service {
|
||||
mForegroundNotifyMsg.setTitle("电池提醒服务运行中");
|
||||
mForegroundNotifyMsg.setContent("后台持续监测电池状态,确保提醒及时");
|
||||
mForegroundNotifyMsg.setRemindMSG("service_running");
|
||||
// 启动前台保活通知
|
||||
startForegroundNotifyImmediately();
|
||||
// 移除:此处不再发送通知,通知已在onCreate中发送
|
||||
}
|
||||
LogUtils.d(TAG, "initNotificationManager: 通知工具类初始化完成");
|
||||
} catch (Exception e) {
|
||||
@@ -226,6 +281,7 @@ public class ControlCenterService extends Service {
|
||||
|
||||
/**
|
||||
* 立即启动前台保活通知(API26+ 前台服务必需)
|
||||
* 注:当前仅作为备用方法,实际已在initForegroundNotificationImmediately中调用
|
||||
*/
|
||||
private void startForegroundNotifyImmediately() {
|
||||
LogUtils.d(TAG, "startForegroundNotifyImmediately: 启动前台保活通知");
|
||||
@@ -243,7 +299,7 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新绑定前台通知(onStartCommand触发,防止保活状态丢失)
|
||||
* 重新绑定前台通知(已删除调用,防止重复执行startForeground)
|
||||
*/
|
||||
private void rebindForegroundNotify() {
|
||||
if (mNotificationManager == null || mNotificationManager.getForegroundServiceNotify() == null) {
|
||||
@@ -447,9 +503,7 @@ public class ControlCenterService extends Service {
|
||||
LogUtils.w(TAG, "handleExternalCommand: 服务已禁用,忽略线程重启指令");
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. 新增:处理应用前台/后台状态同步指令(MainActivity触发)
|
||||
else if (ACTION_SYNC_APP_FOREGROUND_STATE.equals(action)) {
|
||||
} else if (ACTION_SYNC_APP_FOREGROUND_STATE.equals(action)) {
|
||||
boolean isForeground = intent.getBooleanExtra(EXTRA_APP_FOREGROUND_STATE, false);
|
||||
synchronized (mServiceLock) {
|
||||
mIsAppForeground = isForeground;
|
||||
@@ -514,9 +568,10 @@ public class ControlCenterService extends Service {
|
||||
LogUtils.d(TAG, "clearAllReferences: 所有引用已置空");
|
||||
}
|
||||
|
||||
// ================================== 静态工具方法(新增前台状态同步入口,完善保活优化)=================================
|
||||
// ================================== 静态工具方法(修复启停逻辑颠倒问题)=================================
|
||||
/**
|
||||
* 启动服务(静态入口,从本地读取控制配置,显式绑定包名,适配API30+)
|
||||
* 【修复点4:统一使用startForegroundService,适配API26+】
|
||||
*/
|
||||
public static void startControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, "startControlCenterService: 启动服务入口");
|
||||
@@ -524,26 +579,14 @@ public class ControlCenterService extends Service {
|
||||
LogUtils.e(TAG, "startControlCenterService: Context为空,启动失败");
|
||||
return;
|
||||
}
|
||||
if (isServiceRunning(context, ControlCenterService.class)) {
|
||||
LogUtils.d(TAG, "startControlCenterService: 服务已运行,同步本地控制配置");
|
||||
// 服务已运行,触发onStartCommand同步最新配置
|
||||
sendSyncConfigCommand(context);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
LogUtils.d(TAG, "startControlCenterService: 服务启动指令发送成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "startControlCenterService: 启动服务异常", e);
|
||||
// 修复:API26+必须调用startForegroundService,避免系统异常
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(intent);
|
||||
} else {
|
||||
context.startService(intent);
|
||||
}
|
||||
LogUtils.d(TAG, "startControlCenterService: 服务启动指令发送成功");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,19 +598,14 @@ public class ControlCenterService extends Service {
|
||||
LogUtils.e(TAG, "stopControlCenterService: Context为空,停止失败");
|
||||
return;
|
||||
}
|
||||
if (!isServiceRunning(context, ControlCenterService.class)) {
|
||||
LogUtils.d(TAG, "stopControlCenterService: 服务未运行,跳过停止");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.stopService(intent);
|
||||
LogUtils.d(TAG, "stopControlCenterService: 服务停止指令发送成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:更新服务控制配置(本地持久化,动态切换服务启用/禁用状态)
|
||||
* 【修复点5:修复启停逻辑颠倒问题】
|
||||
*/
|
||||
public static void updateServiceControlConfig(Context context, ControlCenterServiceBean controlBean) {
|
||||
LogUtils.d(TAG, "updateServiceControlConfig: 更新服务控制配置,新状态=" + controlBean.isEnableService());
|
||||
@@ -580,32 +618,14 @@ public class ControlCenterService extends Service {
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "updateServiceControlConfig: 控制配置已持久化");
|
||||
|
||||
// 第二步:若服务已运行,触发同步(让服务立即生效)
|
||||
if (isServiceRunning(context, ControlCenterService.class)) {
|
||||
sendSyncConfigCommand(context);
|
||||
LogUtils.d(TAG, "updateServiceControlConfig: 服务已运行,已触发配置同步");
|
||||
} else {
|
||||
// 服务未运行,按需启动服务(根据新配置决定是否启用业务)
|
||||
// 第二步:启停服务(修复:启用则启动,禁用则停止)
|
||||
if (controlBean.isEnableService()) {
|
||||
stopControlCenterService(context);
|
||||
startControlCenterService(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);
|
||||
LogUtils.d(TAG, "updateServiceControlConfig: 服务已设置启动");
|
||||
} else {
|
||||
stopControlCenterService(context);
|
||||
LogUtils.d(TAG, "updateServiceControlConfig: 服务已设置停止");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ public class MainContentView {
|
||||
|
||||
// 配置变更确认对话框(单例复用,避免重复创建)
|
||||
private AlertDialog mConfigConfirmDialog;
|
||||
// 对话框 Builder(核心新增:解决 setMessage 不生效问题)
|
||||
private AlertDialog.Builder mDialogBuilder;
|
||||
// 临时存储变更数据(对话框确认前缓存,取消时恢复)
|
||||
private TempConfigData mTempConfigData;
|
||||
// 对话框状态锁(避免快速点击重复弹窗)
|
||||
@@ -116,7 +118,7 @@ public class MainContentView {
|
||||
// 执行核心初始化流程(按顺序执行,避免依赖空指针)
|
||||
bindViews(rootView);
|
||||
initBatteryDrawables();
|
||||
initConfirmDialog();
|
||||
initConfirmDialog(); // 先初始化对话框,再绑定监听
|
||||
bindViewListeners();
|
||||
|
||||
LogUtils.d(TAG, "constructor: 整体初始化完成");
|
||||
@@ -176,7 +178,7 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化配置变更确认对话框(单例复用,无模式,点击外部关闭,适配 API30 对话框机制)
|
||||
* 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题)
|
||||
*/
|
||||
private void initConfirmDialog() {
|
||||
LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框");
|
||||
@@ -185,29 +187,31 @@ public class MainContentView {
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建无模式对话框(点击外部可关闭,取消改动)
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
builder.setTitle("配置变更确认");
|
||||
// 优化:区分服务开关/普通配置,显示不同提示语(提升用户体验)
|
||||
builder.setMessage("是否确认修改当前配置?");
|
||||
// 1. 初始化 Builder(核心:后续通过 Builder 更新消息)
|
||||
mDialogBuilder = new AlertDialog.Builder(mContext);
|
||||
mDialogBuilder.setTitle("配置变更确认");
|
||||
mDialogBuilder.setMessage("是否确认修改当前配置?");
|
||||
|
||||
// 确定按钮:保存配置+回调+更新视图
|
||||
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
mDialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
confirmConfigChange(); // 确认变更,保存配置
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
// 取消按钮:恢复原始配置(补充物理取消按钮,提升用户体验)
|
||||
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
|
||||
mDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
cancelConfigChange(); // 取消变更,恢复原始值
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
// 对话框外部点击监听:关闭对话框+恢复原始配置
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
mDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
cancelConfigChange(); // 取消变更,恢复原始值
|
||||
@@ -215,8 +219,8 @@ public class MainContentView {
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化对话框实例(设置可取消,支持外部点击关闭)
|
||||
mConfigConfirmDialog = builder.create();
|
||||
// 2. 初始化对话框实例(设置可取消,支持外部点击关闭)
|
||||
mConfigConfirmDialog = mDialogBuilder.create();
|
||||
mConfigConfirmDialog.setCancelable(true);
|
||||
mConfigConfirmDialog.setCanceledOnTouchOutside(true);
|
||||
LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成");
|
||||
@@ -246,6 +250,7 @@ public class MainContentView {
|
||||
}
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress);
|
||||
updateDialogMessageByChangeType(); // 更新提示语
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
|
||||
}
|
||||
@@ -277,6 +282,7 @@ public class MainContentView {
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue);
|
||||
updateDialogMessageByChangeType(); // 更新提示语
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
@@ -297,6 +303,7 @@ public class MainContentView {
|
||||
}
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress);
|
||||
updateDialogMessageByChangeType(); // 更新提示语
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
|
||||
}
|
||||
@@ -328,6 +335,7 @@ public class MainContentView {
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue);
|
||||
updateDialogMessageByChangeType(); // 更新提示语
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
@@ -335,19 +343,21 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成");
|
||||
}
|
||||
|
||||
// 服务总开关监听(核心优化:从 AppConfig 改为读取服务控制Bean,确保状态一致)
|
||||
// 服务总开关监听(核心优化:逻辑与其他控件完全对齐)
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// 关键调整:服务开关状态从服务控制Bean读取,而非AppConfig
|
||||
// 从服务控制Bean读取原始状态,确保与实际一致
|
||||
boolean originalValue = getServiceEnableState();
|
||||
boolean newValue = ((Switch) v).isChecked();
|
||||
// 状态无变化,不处理
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框(优化:服务开关弹窗提示语差异化)
|
||||
// 缓存变更数据
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_SERVICE_SWITCH, originalValue, newValue);
|
||||
// 更新差异化提示语
|
||||
updateDialogMessageByChangeType();
|
||||
// 显示确认对话框
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
@@ -376,7 +386,7 @@ public class MainContentView {
|
||||
int currentVal = mAppConfigUtils.getCurrentBatteryValue();
|
||||
boolean chargeEnable = mAppConfigUtils.isChargeReminderEnabled();
|
||||
boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled();
|
||||
// 关键调整:服务开关状态从服务控制Bean读取,确保与服务实际状态一致
|
||||
// 从服务控制Bean读取状态,确保UI与实际一致
|
||||
boolean serviceEnable = getServiceEnableState();
|
||||
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);
|
||||
LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成");
|
||||
|
||||
// 服务开关+提示文本更新(核心调整:使用服务控制Bean状态)
|
||||
// 服务开关+提示文本更新(确保状态准确)
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(serviceEnable);
|
||||
swEnableService.setText(mContext.getString(R.string.txt_aboveswitch));
|
||||
@@ -471,6 +481,8 @@ public class MainContentView {
|
||||
mConfigConfirmDialog.setOnCancelListener(null);
|
||||
mConfigConfirmDialog = null;
|
||||
}
|
||||
// 释放 Builder
|
||||
mDialogBuilder = null;
|
||||
// 释放临时数据
|
||||
mTempConfigData = null;
|
||||
|
||||
@@ -506,7 +518,7 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:设置服务开关启用状态(外部调用,同步 UI 与服务状态,适配 Activity 视图刷新)
|
||||
* 设置服务开关启用状态(外部调用,同步 UI 与服务状态,适配 Activity 视图刷新)
|
||||
* @param enabled 服务启用状态
|
||||
*/
|
||||
public void setServiceSwitchChecked(boolean enabled) {
|
||||
@@ -517,7 +529,7 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:设置服务开关点击状态(外部调用,避免更新 UI 时触发重复回调)
|
||||
* 设置服务开关点击状态(外部调用,避免更新 UI 时触发重复回调)
|
||||
* @param enabled 是否允许点击
|
||||
*/
|
||||
public void setServiceSwitchEnabled(boolean enabled) {
|
||||
@@ -537,9 +549,9 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用");
|
||||
return;
|
||||
}
|
||||
// 基础校验:对话框/上下文为空
|
||||
if (mConfigConfirmDialog == null || mContext == null) {
|
||||
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框/上下文异常,无法显示");
|
||||
// 基础校验:对话框/上下文/Builder 为空
|
||||
if (mDialogBuilder == null || mContext == null) {
|
||||
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框Builder/上下文异常,无法显示");
|
||||
if (mTempConfigData != null) cancelConfigChange();
|
||||
return;
|
||||
}
|
||||
@@ -550,20 +562,20 @@ public class MainContentView {
|
||||
if (mTempConfigData != null) cancelConfigChange();
|
||||
return;
|
||||
}
|
||||
// 重新构建对话框(核心:确保最新消息生效)
|
||||
mConfigConfirmDialog = mDialogBuilder.create();
|
||||
// 显示对话框,设置状态锁+关闭监听
|
||||
if (!mConfigConfirmDialog.isShowing()) {
|
||||
isDialogShowing = true;
|
||||
mConfigConfirmDialog.show();
|
||||
// 对话框关闭时解锁(无论确认/取消/外部点击,均解锁)
|
||||
mConfigConfirmDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
isDialogShowing = false;
|
||||
mConfigConfirmDialog.setOnDismissListener(null); // 移除监听,避免内存泄漏
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
|
||||
}
|
||||
mConfigConfirmDialog.show();
|
||||
isDialogShowing = true;
|
||||
// 对话框关闭时解锁
|
||||
mConfigConfirmDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
isDialogShowing = false;
|
||||
mConfigConfirmDialog.setOnDismissListener(null);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -576,36 +588,36 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
switch (mTempConfigData.changeType) {
|
||||
// 充电提醒开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
// 充电提醒开关
|
||||
case CHANGE_TYPE_CHARGE_SWITCH:
|
||||
mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue);
|
||||
mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 耗电提醒开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
// 耗电提醒开关
|
||||
case CHANGE_TYPE_USAGE_SWITCH:
|
||||
mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue);
|
||||
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 服务总开关(核心优化:同步更新服务控制Bean,而非AppConfig)
|
||||
// 服务总开关(核心:持久化配置+触发 Activity 回调)
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
// 1. 保存服务控制配置到本地(持久化自启动状态)
|
||||
// 1. 保存服务控制配置到本地
|
||||
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
|
||||
if (serviceBean == null) serviceBean = new ControlCenterServiceBean(false);
|
||||
serviceBean.setIsEnableService(mTempConfigData.newBooleanValue);
|
||||
ControlCenterService.updateServiceControlConfig(mContext, serviceBean);
|
||||
// 2. 回调 Activity,触发服务启停
|
||||
// 2. 强制触发 Activity 回调,执行服务启停逻辑
|
||||
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
|
||||
break;
|
||||
// 充电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
// 充电提醒进度条
|
||||
case CHANGE_TYPE_CHARGE_SEEKBAR:
|
||||
mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue);
|
||||
mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认,值=" + mTempConfigData.newIntValue);
|
||||
break;
|
||||
// 耗电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
// 耗电提醒进度条
|
||||
case CHANGE_TYPE_USAGE_SEEKBAR:
|
||||
mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue);
|
||||
mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue);
|
||||
@@ -630,28 +642,24 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
switch (mTempConfigData.changeType) {
|
||||
// 充电提醒开关:恢复原始状态
|
||||
case CHANGE_TYPE_CHARGE_SWITCH:
|
||||
if (cbEnableChargeReminder != null) {
|
||||
cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 耗电提醒开关:恢复原始状态
|
||||
case CHANGE_TYPE_USAGE_SWITCH:
|
||||
if (cbEnableUsageReminder != null) {
|
||||
cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 服务总开关:恢复原始状态(核心优化:从服务控制Bean读取原始值)
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(mTempConfigData.originalBooleanValue);
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 服务开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 充电提醒进度条:恢复原始进度+更新视图
|
||||
case CHANGE_TYPE_CHARGE_SEEKBAR:
|
||||
if (sbChargeReminder != null) {
|
||||
sbChargeReminder.setProgress(mTempConfigData.originalIntValue);
|
||||
@@ -663,7 +671,6 @@ public class MainContentView {
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消,恢复值=" + mTempConfigData.originalIntValue);
|
||||
break;
|
||||
// 耗电提醒进度条:恢复原始进度+更新视图
|
||||
case CHANGE_TYPE_USAGE_SEEKBAR:
|
||||
if (sbUsageReminder != null) {
|
||||
sbUsageReminder.setProgress(mTempConfigData.originalIntValue);
|
||||
@@ -705,7 +712,7 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:获取服务启用状态(统一从服务控制Bean读取,确保全链路状态一致)
|
||||
* 获取服务启用状态(统一从服务控制Bean读取,确保全链路状态一致)
|
||||
* @return 服务启用状态(true=启用,false=禁用)
|
||||
*/
|
||||
private boolean getServiceEnableState() {
|
||||
@@ -715,17 +722,22 @@ public class MainContentView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:根据变更类型更新对话框提示语(差异化提示,提升用户体验)
|
||||
* 根据变更类型更新对话框提示语(核心优化:通过 Builder 更新,确保生效)
|
||||
*/
|
||||
private void updateDialogMessageByChangeType() {
|
||||
if (mConfigConfirmDialog == null || mTempConfigData == null) return;
|
||||
if (mDialogBuilder == null || mTempConfigData == null) return;
|
||||
String message;
|
||||
if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) {
|
||||
message = mTempConfigData.newBooleanValue ? "启用服务后,将后台持续监控电池状态,是否确认?" : "禁用服务后,电池监控功能将停止,是否确认?";
|
||||
// 服务开关差异化提示语
|
||||
message = mTempConfigData.newBooleanValue ?
|
||||
"启用服务后,将后台持续监控电池状态,是否确认?" :
|
||||
"禁用服务后,电池监控功能将停止,是否确认?";
|
||||
} else {
|
||||
// 普通配置默认提示语
|
||||
message = "是否确认修改当前配置?";
|
||||
}
|
||||
mConfigConfirmDialog.setMessage(message);
|
||||
// 通过 Builder 设置消息,确保弹窗显示最新内容
|
||||
mDialogBuilder.setMessage(message);
|
||||
}
|
||||
|
||||
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
|
||||
|
||||
Reference in New Issue
Block a user