添加滚动条拉动时,实时预览数值的功能。

This commit is contained in:
2025-12-20 19:26:32 +08:00
parent 79ae6de6fc
commit 35d210c378
4 changed files with 411 additions and 305 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sat Dec 20 18:45:13 HKT 2025
#Sat Dec 20 11:24:15 GMT 2025
stageCount=11
libraryProject=
baseVersion=15.14
publishVersion=15.14.10
buildCount=0
buildCount=2
baseBetaVersion=15.14.11

View File

@@ -41,14 +41,11 @@ import cc.winboll.studio.powerbell.views.MainContentView;
* 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
*/
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
public static final String TAG = "MainActivity";
// 请求码常量
// ======================== 静态常量(置顶统一,抽离魔法值)========================
public static final String TAG = "MainActivity";
private static final int REQUEST_READ_MEDIA_IMAGES = 1001;
// 延迟加载常量(非核心视图延迟加载时长)
private static final long DELAY_LOAD_NON_CRITICAL = 500L;
// Handler消息标识按业务优先级排序
public static final int MSG_RELOAD_APPCONFIG = 0;
public static final int MSG_CURRENTVALUEBATTERY = 1;
public static final int MSG_LOAD_BACKGROUND = 2;
@@ -75,7 +72,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
private Drawable mFrameDrawable;
private Menu mMenu;
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环========================
// ======================== 生命周期方法(按系统调用顺序排列)========================
@Override
public Activity getActivity() {
return this;
@@ -88,12 +85,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 页面启动,开始初始化流程 | savedInstanceState=" + savedInstanceState);
super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate() | savedInstanceState=" + savedInstanceState);
// 优先初始化全局Handler避免消息丢失
initGlobalHandler();
// 布局与核心流程初始化
setContentView(R.layout.activity_main);
initPermissionUtils();
initMainContentView();
@@ -105,62 +100,56 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
LogUtils.d(TAG, "onPostCreate() | savedInstanceState=" + savedInstanceState);
mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
}
@Override
protected void onResume() {
super.onResume();
LogUtils.d(TAG, "onResume: 恢复页面状态");
// 恢复背景与服务开关UI
LogUtils.d(TAG, "onResume()");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "onResume: 发送背景加载与服务开关更新消息");
}
// 恢复广告
if (mADsBannerView != null) {
mADsBannerView.resumeADs(this);
LogUtils.d(TAG, "onResume: 广告视图恢复展示");
}
}
@Override
protected void onPause() {
super.onPause();
LogUtils.d(TAG, "onPause: 页面暂停");
LogUtils.d(TAG, "onPause()");
}
@Override
protected void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 开始释放资源");
LogUtils.d(TAG, "onDestroy()");
// 释放广告资源
if (mADsBannerView != null) {
mADsBannerView.releaseAdResources();
mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 广告资源已释放");
}
// 释放核心视图
if (mMainContentView != null) {
mMainContentView.releaseResources();
mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
}
// 销毁Handler防止内存泄漏
if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 全局Handler已销毁");
}
// 释放Drawable,清空回调
// 释放Drawable
if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null);
mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 框架背景Drawable已释放");
}
// 置空所有引用帮助GC回收
// 置空所有引用
sMainActivity = null;
mPermissionUtils = null;
mAppConfigUtils = null;
@@ -170,31 +159,27 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mApplication = null;
mToolbar = null;
mAdsViewStub = null;
LogUtils.d(TAG, "onDestroy: 所有资源释放完成");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data);
LogUtils.d(TAG, "onActivityResult() | requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 背景设置完成后重新加载
if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送重新加载消息");
}
}
// ======================== 菜单与导航方法 ========================
@Override
public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu: 初始化菜单");
LogUtils.d(TAG, "onCreateOptionsMenu() | menu=" + menu);
mMenu = menu;
AESThemeUtil.inflateMenu(this, menu);
if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载单元测试菜单");
}
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
return true;
@@ -202,7 +187,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected: 菜单点击 | itemId=" + item.getItemId());
LogUtils.d(TAG, "onOptionsItemSelected() | itemId=" + item.getItemId());
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate();
return true;
@@ -213,27 +198,21 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
switch (item.getItemId()) {
case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转设置页面");
break;
case R.id.action_battery_report:
startActivity(new Intent(this, BatteryReportActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转电池报告页面");
break;
case R.id.action_clearrecord:
startActivity(new Intent(this, ClearRecordActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转记录清理页面");
break;
case R.id.action_changepicture:
startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES);
LogUtils.d(TAG, "onOptionsItemSelected: 跳转背景设置页面 | requestCode=" + REQUEST_READ_MEDIA_IMAGES);
break;
case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转单元测试页面");
break;
case R.id.action_about:
startAboutActivity();
LogUtils.d(TAG, "onOptionsItemSelected: 跳转关于页面");
break;
default:
return super.onOptionsItemSelected(item);
@@ -244,41 +223,41 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void setupToolbar() {
super.setupToolbar();
LogUtils.d(TAG, "setupToolbar()");
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 隐藏返回按钮");
}
}
@Override
public void onBackPressed() {
LogUtils.d(TAG, "onBackPressed()");
moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用退至后台");
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
LogUtils.d(TAG, "dispatchKeyEvent() | event=" + event);
return super.dispatchKeyEvent(event);
}
// ======================== 核心初始化方法 ========================
private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: 初始化权限工具类");
LogUtils.d(TAG, "initPermissionUtils()");
mPermissionUtils = PermissionUtils.getInstance();
}
private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: 初始化全局Handler");
LogUtils.d(TAG, "initGlobalHandler()");
if (sGlobalHandler == null) {
sGlobalHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what=" + msg.what);
return;
}
LogUtils.d(TAG, "handleMessage: 处理消息 | what=" + msg.what);
LogUtils.d(TAG, "handleMessage() | what=" + msg.what);
switch (msg.what) {
case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData();
@@ -299,30 +278,28 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
}
};
LogUtils.d(TAG, "initGlobalHandler: 全局Handler创建成功");
}
}
private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: 初始化核心视图");
LogUtils.d(TAG, "initMainContentView()");
View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this);
}
private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: 初始化关键视图组件");
LogUtils.d(TAG, "initCriticalView()");
sMainActivity = this;
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
}
mAdsViewStub = findViewById(R.id.stub_ads_banner);
}
private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步初始化核心工具类");
LogUtils.d(TAG, "initCoreUtilsAsync()");
new Thread(new Runnable() {
@Override
public void run() {
@@ -336,7 +313,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无配置,创建默认禁用配置");
}
// 根据配置启停服务
@@ -348,7 +324,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void run() {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 配置启用服务,启动服务");
}
});
} else if (!isServiceEnable && isServiceAlive) {
@@ -356,7 +331,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 配置禁用服务,停止服务");
}
});
}
@@ -380,13 +354,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
}
});
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程执行完成");
}
}).start();
}
private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 延迟加载非核心视图 | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms");
LogUtils.d(TAG, "loadNonCriticalViewDelayed() | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
@@ -401,7 +374,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 视图操作方法 ========================
private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 加载广告视图");
LogUtils.d(TAG, "loadAdsView()");
if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空加载失败");
return;
@@ -409,22 +382,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: 广告视图创建成功");
}
}
private void updateViewData() {
LogUtils.d(TAG, "updateViewData: 更新视图数据");
LogUtils.d(TAG, "updateViewData()");
if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图或框架背景为空,更新失败");
return;
}
mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
}
private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: 重新加载背景");
LogUtils.d(TAG, "reloadBackground()");
if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图或背景工具类为空,加载失败");
return;
@@ -432,15 +403,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
LogUtils.d(TAG, "reloadBackground: 加载自定义背景成功");
} else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
LogUtils.w(TAG, "reloadBackground: 无自定义背景,使用默认背景");
}
}
private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 设置主布局背景色");
LogUtils.d(TAG, "setMainLayoutBackgroundColor()");
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败");
return;
@@ -453,41 +422,34 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI: 更新服务开关UI状态");
LogUtils.d(TAG, "updateServiceSwitchUI()");
if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图或服务配置为空,更新失败");
return;
}
boolean configEnabled = mServiceControlBean.isEnableService();
LogUtils.d(TAG, "updateServiceSwitchUI: 服务配置启用状态=" + configEnabled);
mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI状态更新完成");
}
// ======================== 服务与线程管理方法 ========================
private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: 切换服务状态 | 目标状态=" + isEnable);
LogUtils.d(TAG, "toggleServiceEnableState() | 目标状态=" + isEnable);
if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return;
}
mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 服务配置已保存");
// UI开关联动服务启停
if (isEnable) {
// 开启:启动服务
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动");
}
} else {
// 关闭:停止服务
ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
}
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
@@ -495,7 +457,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 页面跳转方法 ========================
private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: 启动关于页面");
LogUtils.d(TAG, "startAboutActivity()");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
@@ -504,14 +466,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 消息发送方法 ========================
private void notifyServiceAppConfigChange() {
LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更");
LogUtils.d(TAG, "notifyServiceAppConfigChange()");
ControlCenterService.sendAppConfigStatusUpdateMessage(this);
reloadAppConfig();
}
// ======================== 静态工具方法 ========================
public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: 发送配置重载消息");
LogUtils.d(TAG, "reloadAppConfig()");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
} else {
@@ -520,7 +481,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
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;
@@ -532,7 +493,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 辅助工具方法 ========================
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 生成默认应用信息");
LogUtils.d(TAG, "genDefaultAppInfo()");
String branchName = "powerbell";
APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name));
@@ -551,31 +512,31 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== MainContentView 事件回调 ========================
@Override
public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 充电提醒开关状态变更 | isChecked=" + isChecked);
LogUtils.d(TAG, "onChargeReminderSwitchChanged() | isChecked=" + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 耗电提醒开关状态变更 | isChecked=" + isChecked);
LogUtils.d(TAG, "onUsageReminderSwitchChanged() | isChecked=" + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 服务总开关状态变更 | isChecked=" + isChecked);
LogUtils.d(TAG, "onServiceSwitchChanged() | isChecked=" + isChecked);
toggleServiceEnableState(isChecked);
}
@Override
public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: 充电提醒阈值变更 | progress=" + progress);
LogUtils.d(TAG, "onChargeReminderProgressChanged() | progress=" + progress);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: 耗电提醒阈值变更 | progress=" + progress);
LogUtils.d(TAG, "onUsageReminderProgressChanged() | progress=" + progress);
notifyServiceAppConfigChange();
}
}

View File

@@ -24,12 +24,55 @@ import cc.winboll.studio.powerbell.utils.AppConfigUtils;
* @Date 2025/12/17 13:14
* @Describe 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑
* 适配Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏,配置变更确认对话框
* 新增:拖动进度条时实时预览 sbUsageReminder 与 sbChargeReminder 比值
*/
public class MainContentView {
// ======================== 静态常量(置顶,唯一标识)========================
public static final String TAG = "MainContentView";
// ======================== 核心成员变量(按「依赖→视图→内部资源→对话框」排序)========================
// 变更类型常量(区分不同控件,精准处理逻辑)
private static final int CHANGE_TYPE_CHARGE_SWITCH = 1;
private static final int CHANGE_TYPE_USAGE_SWITCH = 2;
private static final int CHANGE_TYPE_SERVICE_SWITCH = 3;
private static final int CHANGE_TYPE_CHARGE_SEEKBAR = 4;
private static final int CHANGE_TYPE_USAGE_SEEKBAR = 5;
// ======================== 内部静态类(临时数据载体,避免外部依赖)========================
/**
* 临时配置数据实体(缓存变更信息,取消时恢复)
*/
private static class TempConfigData {
int changeType;
boolean originalBooleanValue;
int originalIntValue;
boolean newBooleanValue;
int newIntValue;
// 构造方法(开关类型)
TempConfigData(int changeType, boolean originalValue, boolean newValue) {
this.changeType = changeType;
this.originalBooleanValue = originalValue;
this.newBooleanValue = newValue;
}
// 构造方法(进度条类型)
TempConfigData(int changeType, int originalValue, int newValue) {
this.changeType = changeType;
this.originalIntValue = originalValue;
this.newIntValue = newValue;
}
}
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
public interface OnViewActionListener {
void onChargeReminderSwitchChanged(boolean isChecked);
void onUsageReminderSwitchChanged(boolean isChecked);
void onServiceSwitchChanged(boolean isChecked);
void onChargeReminderProgressChanged(int progress);
void onUsageReminderProgressChanged(int progress);
}
// ======================== 成员变量(按功能分类,避免混乱)========================
// 外部依赖实例(生命周期关联,优先声明)
private Context mContext;
private AppConfigUtils mAppConfigUtils;
@@ -59,6 +102,10 @@ public class MainContentView {
public ImageView ivChargeReminderBattery;
public ImageView ivUsageReminderBattery;
// 进度缓存(用于实时计算比值,避免频繁调用 getProgress()
private int mCurrentChargeProgress;
private int mCurrentUsageProgress;
// 内部复用资源(避免重复创建,优化性能)
private BatteryDrawable mCurrentBatteryDrawable;
private BatteryDrawable mChargeReminderBatteryDrawable;
@@ -66,62 +113,27 @@ public class MainContentView {
// 配置变更确认对话框(单例复用,避免重复创建)
private AlertDialog mConfigConfirmDialog;
// 对话框 Builder核心新增解决 setMessage 不生效问题)
private AlertDialog.Builder mDialogBuilder;
// 临时存储变更数据(对话框确认前缓存,取消时恢复)
private TempConfigData mTempConfigData;
// 对话框状态锁(避免快速点击重复弹窗)
private boolean isDialogShowing = false;
// ======================== 临时配置数据实体(缓存变更信息,取消时恢复)========================
private static class TempConfigData {
// 变更类型(区分开关/进度条,避免混淆)
int changeType;
// 原始值(取消时恢复用)
boolean originalBooleanValue;
int originalIntValue;
// 变更后的值(确认时保存用)
boolean newBooleanValue;
int newIntValue;
// 构造方法(开关类型)
TempConfigData(int changeType, boolean originalValue, boolean newValue) {
this.changeType = changeType;
this.originalBooleanValue = originalValue;
this.newBooleanValue = newValue;
}
// 构造方法(进度条类型)
TempConfigData(int changeType, int originalValue, int newValue) {
this.changeType = changeType;
this.originalIntValue = originalValue;
this.newIntValue = newValue;
}
}
// 变更类型常量(区分不同控件,精准处理逻辑)
private static final int CHANGE_TYPE_CHARGE_SWITCH = 1;
private static final int CHANGE_TYPE_USAGE_SWITCH = 2;
private static final int CHANGE_TYPE_SERVICE_SWITCH = 3;
private static final int CHANGE_TYPE_CHARGE_SEEKBAR = 4;
private static final int CHANGE_TYPE_USAGE_SEEKBAR = 5;
// ======================== 构造方法(初始化入口,逻辑闭环)========================
public MainContentView(Context context, View rootView, OnViewActionListener actionListener) {
LogUtils.d(TAG, "constructor: 开始初始化");
LogUtils.d(TAG, "MainContentView() | context=" + context + " | rootView=" + rootView + " | actionListener=" + actionListener);
// 初始化外部依赖
this.mContext = context;
this.mActionListener = actionListener;
this.mAppConfigUtils = AppConfigUtils.getInstance(context.getApplicationContext());
LogUtils.d(TAG, "constructor: 外部依赖初始化完成");
// 执行核心初始化流程(按顺序执行,避免依赖空指针)
bindViews(rootView);
initBatteryDrawables();
initConfirmDialog(); // 先初始化对话框,再绑定监听
initConfirmDialog();
bindViewListeners();
LogUtils.d(TAG, "constructor: 整体初始化完成");
LogUtils.d(TAG, "MainContentView 初始化完成");
}
// ======================== 私有初始化方法(封装内部逻辑,仅暴露入口)========================
@@ -129,7 +141,7 @@ public class MainContentView {
* 绑定视图控件(显式强转适配 Java7适配 API30 视图加载机制)
*/
private void bindViews(View rootView) {
LogUtils.d(TAG, "bindViews: 开始绑定视图");
LogUtils.d(TAG, "bindViews() | rootView=" + rootView);
// 基础布局绑定
mainLayout = (RelativeLayout) rootView.findViewById(R.id.activitymainRelativeLayout1);
backgroundView = (BackgroundView) rootView.findViewById(R.id.fragmentmainviewBackgroundView1);
@@ -153,17 +165,20 @@ public class MainContentView {
ivChargeReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView3);
ivUsageReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView2);
// 初始化进度缓存(从配置读取初始值)
mCurrentChargeProgress = mAppConfigUtils.getChargeReminderValue();
mCurrentUsageProgress = mAppConfigUtils.getUsageReminderValue();
// 关键视图绑定校验(仅保留核心控件错误日志,精简冗余)
if (mainLayout == null) LogUtils.e(TAG, "bindViews: mainLayout 绑定失败");
if (backgroundView == null) LogUtils.e(TAG, "bindViews: backgroundView 绑定失败");
LogUtils.d(TAG, "bindViews: 视图绑定完成");
if (mainLayout == null) LogUtils.e(TAG, "mainLayout 绑定失败");
if (backgroundView == null) LogUtils.e(TAG, "backgroundView 绑定失败");
}
/**
* 初始化电池 Drawable集成 BatteryDrawable默认能量风格适配小米机型渲染
*/
private void initBatteryDrawables() {
LogUtils.d(TAG, "initBatteryDrawables: 开始初始化电池 Drawable");
LogUtils.d(TAG, "initBatteryDrawables()");
// 当前电量 Drawable颜色从资源读取适配 API30 主题)
int colorCurrent = getResourceColor(R.color.colorCurrent);
mCurrentBatteryDrawable = new BatteryDrawable(colorCurrent);
@@ -173,17 +188,15 @@ public class MainContentView {
// 耗电提醒 Drawable
int colorUsage = getResourceColor(R.color.colorUsege);
mUsageReminderBatteryDrawable = new BatteryDrawable(colorUsage);
LogUtils.d(TAG, "initBatteryDrawables: 电池 Drawable 初始化完成");
}
/**
* 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题)
*/
private void initConfirmDialog() {
LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框");
LogUtils.d(TAG, "initConfirmDialog()");
if (mContext == null) {
LogUtils.e(TAG, "initConfirmDialog: Context 为空,初始化失败");
LogUtils.e(TAG, "Context 为空,初始化失败");
return;
}
@@ -196,7 +209,7 @@ public class MainContentView {
mDialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
confirmConfigChange(); // 确认变更,保存配置
confirmConfigChange();
dialog.dismiss();
}
});
@@ -205,7 +218,7 @@ public class MainContentView {
mDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cancelConfigChange(); // 取消变更,恢复原始值
cancelConfigChange();
dialog.dismiss();
}
});
@@ -214,7 +227,7 @@ public class MainContentView {
mDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
cancelConfigChange(); // 取消变更,恢复原始值
cancelConfigChange();
dialog.dismiss();
}
});
@@ -223,22 +236,22 @@ public class MainContentView {
mConfigConfirmDialog = mDialogBuilder.create();
mConfigConfirmDialog.setCancelable(true);
mConfigConfirmDialog.setCanceledOnTouchOutside(true);
LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成");
}
/**
* 绑定视图事件监听Java7 显式实现接口,适配 API30 事件分发,修复进度条弹窗失效)
*/
private void bindViewListeners() {
LogUtils.d(TAG, "bindViewListeners: 开始绑定事件监听");
LogUtils.d(TAG, "bindViewListeners()");
// 依赖校验,避免空指针
if (mAppConfigUtils == null || mActionListener == null || mConfigConfirmDialog == null) {
LogUtils.e(TAG, "bindViewListeners: 依赖实例为空,跳过监听绑定");
LogUtils.e(TAG, "依赖实例为空,跳过监听绑定");
return;
}
// 充电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发)
if (sbChargeReminder != null) {
// 原有:触摸抬起/取消监听(用于配置确认)
sbChargeReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
@Override
public void onTouchUp(VerticalSeekBar seekBar, int progress) {
@@ -250,9 +263,9 @@ public class MainContentView {
}
// 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语
updateDialogMessageByChangeType();
showConfigConfirmDialog();
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
LogUtils.d(TAG, "ChargeReminderSeekBar触摸抬起 | 原始值=" + originalValue + " | 新进度=" + progress);
}
@Override
@@ -265,10 +278,34 @@ public class MainContentView {
tvChargeReminderValue.setText(originalValue + "%");
}
seekBar.setProgress(originalValue);
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸取消,进度回滚至=" + originalValue);
// 恢复进度缓存
mCurrentChargeProgress = originalValue;
LogUtils.d(TAG, "ChargeReminderSeekBar触摸取消 | 进度回滚至=" + originalValue);
}
});
LogUtils.d(TAG, "bindViewListeners: 充电提醒进度条专属监听绑定完成");
// 新增:实时进度变化监听(用于比值预览)
sbChargeReminder.setOnVerticalSeekBarChangeListener(new VerticalSeekBar.OnVerticalSeekBarChangeListener() {
@Override
public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mCurrentChargeProgress = progress;
// 同步更新进度文本和电池图标保持UI一致性
if (tvChargeReminderValue != null && mChargeReminderBatteryDrawable != null && ivChargeReminderBattery != null) {
mChargeReminderBatteryDrawable.setBatteryValue(progress);
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
tvChargeReminderValue.setText(progress + "%");
}
}
}
@Override
public void onStartTrackingTouch(VerticalSeekBar seekBar) {}
@Override
public void onStopTrackingTouch(VerticalSeekBar seekBar) {}
});
LogUtils.d(TAG, "充电提醒进度条专属监听绑定完成");
}
// 充电提醒开关监听
@@ -282,16 +319,17 @@ public class MainContentView {
if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语
updateDialogMessageByChangeType();
showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
LogUtils.d(TAG, "cbEnableChargeReminder点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
}
});
LogUtils.d(TAG, "bindViewListeners: 充电提醒开关监听绑定完成");
LogUtils.d(TAG, "充电提醒开关监听绑定完成");
}
// 耗电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发)
if (sbUsageReminder != null) {
// 原有:触摸抬起/取消监听(用于配置确认)
sbUsageReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
@Override
public void onTouchUp(VerticalSeekBar seekBar, int progress) {
@@ -303,9 +341,9 @@ public class MainContentView {
}
// 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语
updateDialogMessageByChangeType();
showConfigConfirmDialog();
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress);
LogUtils.d(TAG, "UsageReminderSeekBar触摸抬起 | 原始值=" + originalValue + " | 新进度=" + progress);
}
@Override
@@ -318,10 +356,34 @@ public class MainContentView {
tvUsageReminderValue.setText(originalValue + "%");
}
seekBar.setProgress(originalValue);
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸取消,进度回滚至=" + originalValue);
// 恢复进度缓存
mCurrentUsageProgress = originalValue;
LogUtils.d(TAG, "UsageReminderSeekBar触摸取消 | 进度回滚至=" + originalValue);
}
});
LogUtils.d(TAG, "bindViewListeners: 耗电提醒进度条专属监听绑定完成");
// 新增:实时进度变化监听(用于比值预览)
sbUsageReminder.setOnVerticalSeekBarChangeListener(new VerticalSeekBar.OnVerticalSeekBarChangeListener() {
@Override
public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mCurrentUsageProgress = progress;
// 同步更新进度文本和电池图标保持UI一致性
if (tvUsageReminderValue != null && mUsageReminderBatteryDrawable != null && ivUsageReminderBattery != null) {
mUsageReminderBatteryDrawable.setBatteryValue(progress);
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
tvUsageReminderValue.setText(progress + "%");
}
}
}
@Override
public void onStartTrackingTouch(VerticalSeekBar seekBar) {}
@Override
public void onStopTrackingTouch(VerticalSeekBar seekBar) {}
});
LogUtils.d(TAG, "耗电提醒进度条专属监听绑定完成");
}
// 耗电提醒开关监听
@@ -335,12 +397,12 @@ public class MainContentView {
if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语
updateDialogMessageByChangeType();
showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
LogUtils.d(TAG, "cbEnableUsageReminder点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
}
});
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成");
LogUtils.d(TAG, "耗电提醒开关监听绑定完成");
}
// 服务总开关监听(核心优化:逻辑与其他控件完全对齐)
@@ -359,13 +421,13 @@ public class MainContentView {
updateDialogMessageByChangeType();
// 显示确认对话框
showConfigConfirmDialog();
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
LogUtils.d(TAG, "swEnableService点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
}
});
LogUtils.d(TAG, "bindViewListeners: 服务总开关监听绑定完成");
LogUtils.d(TAG, "服务总开关监听绑定完成");
}
LogUtils.d(TAG, "bindViewListeners: 所有事件监听绑定完成");
LogUtils.d(TAG, "所有事件监听绑定完成");
}
// ======================== 对外暴露核心方法(业务入口,精简参数,明确职责)========================
@@ -374,9 +436,9 @@ public class MainContentView {
* @param frameDrawable 进度条背景 Drawable外部传入适配主题切换
*/
public void updateViewData(Drawable frameDrawable) {
LogUtils.d(TAG, "updateViewData: 开始更新视图数据");
LogUtils.d(TAG, "updateViewData() | frameDrawable=" + frameDrawable);
if (mAppConfigUtils == null) {
LogUtils.e(TAG, "updateViewData: AppConfigUtils 为空,跳过更新");
LogUtils.e(TAG, "AppConfigUtils 为空,跳过更新");
return;
}
@@ -388,13 +450,15 @@ public class MainContentView {
boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled();
// 从服务控制Bean读取状态确保UI与实际一致
boolean serviceEnable = getServiceEnableState();
LogUtils.d(TAG, "updateViewData: 配置数据读取完成charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal + ", serviceEnable=" + serviceEnable);
// 更新进度缓存
mCurrentChargeProgress = chargeVal;
mCurrentUsageProgress = usageVal;
LogUtils.d(TAG, "配置数据读取完成 | charge=" + chargeVal + " | usage=" + usageVal + " | current=" + currentVal + " | serviceEnable=" + serviceEnable);
// 进度条背景更新
if (frameDrawable != null) {
if (llLeftSeekBar != null) llLeftSeekBar.setBackground(frameDrawable);
if (llRightSeekBar != null) llRightSeekBar.setBackground(frameDrawable);
LogUtils.d(TAG, "updateViewData: 进度条背景更新完成");
}
// 当前电量更新(联动 BatteryDrawable实时刷新图标
@@ -406,7 +470,6 @@ public class MainContentView {
tvCurrentBatteryValue.setTextColor(getResourceColor(R.color.colorCurrent));
tvCurrentBatteryValue.setText(currentVal + "%");
}
LogUtils.d(TAG, "updateViewData: 当前电量视图更新完成");
// 充电提醒视图更新
if (ivChargeReminderBattery != null && mChargeReminderBatteryDrawable != null) {
@@ -419,7 +482,6 @@ public class MainContentView {
}
if (sbChargeReminder != null) sbChargeReminder.setProgress(chargeVal);
if (cbEnableChargeReminder != null) cbEnableChargeReminder.setChecked(chargeEnable);
LogUtils.d(TAG, "updateViewData: 充电提醒视图更新完成");
// 耗电提醒视图更新
if (ivUsageReminderBattery != null && mUsageReminderBatteryDrawable != null) {
@@ -432,7 +494,6 @@ public class MainContentView {
}
if (sbUsageReminder != null) sbUsageReminder.setProgress(usageVal);
if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable);
LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成");
// 服务开关+提示文本更新(确保状态准确)
if (swEnableService != null) {
@@ -440,9 +501,8 @@ public class MainContentView {
swEnableService.setText(mContext.getString(R.string.txt_aboveswitch));
}
if (tvTips != null) tvTips.setText(mContext.getString(R.string.txt_aboveswitchtips));
LogUtils.d(TAG, "updateViewData: 服务开关及提示文本更新完成");
LogUtils.d(TAG, "updateViewData: 所有视图数据更新完成");
LogUtils.d(TAG, "所有视图数据更新完成");
}
/**
@@ -450,10 +510,10 @@ public class MainContentView {
* @param value 电量值(自动校准 0-100避免异常值
*/
public void updateCurrentBattery(int value) {
LogUtils.d(TAG, "updateCurrentBattery: 开始更新,原始值=" + value);
LogUtils.d(TAG, "updateCurrentBattery() | 原始值=" + value);
// 核心依赖校验
if (tvCurrentBatteryValue == null || mCurrentBatteryDrawable == null || ivCurrentBattery == null) {
LogUtils.e(TAG, "updateCurrentBattery: 视图/Drawable 为空,跳过更新");
LogUtils.e(TAG, "视图/Drawable 为空,跳过更新");
return;
}
@@ -464,14 +524,14 @@ public class MainContentView {
ivCurrentBattery.setImageDrawable(mCurrentBatteryDrawable);
tvCurrentBatteryValue.setText(validValue + "%");
LogUtils.d(TAG, "updateCurrentBattery: 更新完成校准后值=" + validValue);
LogUtils.d(TAG, "更新完成 | 校准后值=" + validValue);
}
/**
* 释放资源(主动回收,适配 API30 资源管控机制,优化小米手机内存占用)
*/
public void releaseResources() {
LogUtils.d(TAG, "releaseResources: 开始释放资源");
LogUtils.d(TAG, "releaseResources()");
// 释放对话框资源(安全销毁,避免内存泄漏)
if (mConfigConfirmDialog != null) {
if (mConfigConfirmDialog.isShowing()) {
@@ -514,7 +574,7 @@ public class MainContentView {
mAppConfigUtils = null;
mActionListener = null;
LogUtils.d(TAG, "releaseResources: 所有资源释放完成");
LogUtils.d(TAG, "所有资源释放完成");
}
/**
@@ -522,9 +582,9 @@ public class MainContentView {
* @param enabled 服务启用状态
*/
public void setServiceSwitchChecked(boolean enabled) {
LogUtils.d(TAG, "setServiceSwitchChecked() | enabled=" + enabled);
if (swEnableService != null) {
swEnableService.setChecked(enabled);
LogUtils.d(TAG, "setServiceSwitchChecked: 服务开关UI更新为=" + enabled);
}
}
@@ -533,9 +593,9 @@ public class MainContentView {
* @param enabled 是否允许点击
*/
public void setServiceSwitchEnabled(boolean enabled) {
LogUtils.d(TAG, "setServiceSwitchEnabled() | enabled=" + enabled);
if (swEnableService != null) {
swEnableService.setEnabled(enabled);
LogUtils.d(TAG, "setServiceSwitchEnabled: 服务开关点击状态更新为=" + enabled);
}
}
@@ -544,21 +604,22 @@ public class MainContentView {
* 显示配置变更确认对话框(确保 Activity 处于前台,避免异常,防止重复弹窗)
*/
private void showConfigConfirmDialog() {
LogUtils.d(TAG, "showConfigConfirmDialog() | isDialogShowing=" + isDialogShowing);
// 对话框状态锁:正在显示则跳过,避免重复触发
if (isDialogShowing) {
LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用");
LogUtils.d(TAG, "对话框已显示,跳过重复调用");
return;
}
// 基础校验:对话框/上下文/Builder 为空
if (mDialogBuilder == null || mContext == null) {
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框Builder/上下文异常,无法显示");
LogUtils.e(TAG, "对话框Builder/上下文异常,无法显示");
if (mTempConfigData != null) cancelConfigChange();
return;
}
// Activity 状态校验:避免销毁后弹窗崩溃(适配 API30
Activity activity = (Activity) mContext;
if (activity.isFinishing() || activity.isDestroyed()) {
LogUtils.e(TAG, "showConfigConfirmDialog: Activity 已销毁,无法显示对话框");
LogUtils.e(TAG, "Activity 已销毁,无法显示对话框");
if (mTempConfigData != null) cancelConfigChange();
return;
}
@@ -575,15 +636,16 @@ public class MainContentView {
mConfigConfirmDialog.setOnDismissListener(null);
}
});
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功");
LogUtils.d(TAG, "确认对话框显示成功");
}
/**
* 确认配置变更(保存数据+回调监听+更新视图)
*/
private void confirmConfigChange() {
LogUtils.d(TAG, "confirmConfigChange() | mTempConfigData=" + mTempConfigData);
if (mTempConfigData == null || mAppConfigUtils == null || mActionListener == null) {
LogUtils.e(TAG, "confirmConfigChange: 依赖数据为空,确认失败");
LogUtils.e(TAG, "依赖数据为空,确认失败");
return;
}
@@ -592,40 +654,40 @@ public class MainContentView {
case CHANGE_TYPE_CHARGE_SWITCH:
mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认值=" + mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "充电提醒开关确认 | 值=" + mTempConfigData.newBooleanValue);
break;
// 耗电提醒开关
case CHANGE_TYPE_USAGE_SWITCH:
mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认值=" + mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "耗电提醒开关确认 | 值=" + mTempConfigData.newBooleanValue);
break;
// 服务总开关(核心:持久化配置+触发 Activity 回调)
case CHANGE_TYPE_SERVICE_SWITCH:
// 1. 设置服务启停
if (mTempConfigData.newBooleanValue) {
ControlCenterService.startControlCenterService(mContext);
} else {
ControlCenterService.stopControlCenterService(mContext);
}
if (mTempConfigData.newBooleanValue) {
ControlCenterService.startControlCenterService(mContext);
} else {
ControlCenterService.stopControlCenterService(mContext);
}
// 2. 强制触发 Activity 回调,执行服务启停逻辑
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
LogUtils.d(TAG, "服务开关确认 | 值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
break;
// 充电提醒进度条
case CHANGE_TYPE_CHARGE_SEEKBAR:
mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue);
mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认值=" + mTempConfigData.newIntValue);
LogUtils.d(TAG, "充电提醒进度确认 | 值=" + mTempConfigData.newIntValue);
break;
// 耗电提醒进度条
case CHANGE_TYPE_USAGE_SEEKBAR:
mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue);
mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue);
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒进度确认值=" + mTempConfigData.newIntValue);
LogUtils.d(TAG, "耗电提醒进度确认 | 值=" + mTempConfigData.newIntValue);
break;
default:
LogUtils.w(TAG, "confirmConfigChange: 未知变更类型,跳过");
LogUtils.w(TAG, "未知变更类型,跳过");
break;
}
@@ -637,8 +699,9 @@ public class MainContentView {
* 取消配置变更(恢复原始值+刷新视图,确保 UI 与配置一致)
*/
private void cancelConfigChange() {
LogUtils.d(TAG, "cancelConfigChange() | mTempConfigData=" + mTempConfigData);
if (mTempConfigData == null || mAppConfigUtils == null) {
LogUtils.e(TAG, "cancelConfigChange: 依赖数据为空,取消失败");
LogUtils.e(TAG, "依赖数据为空,取消失败");
return;
}
@@ -647,19 +710,19 @@ public class MainContentView {
if (cbEnableChargeReminder != null) {
cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue);
}
LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消恢复值=" + mTempConfigData.originalBooleanValue);
LogUtils.d(TAG, "充电提醒开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break;
case CHANGE_TYPE_USAGE_SWITCH:
if (cbEnableUsageReminder != null) {
cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue);
}
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消恢复值=" + mTempConfigData.originalBooleanValue);
LogUtils.d(TAG, "耗电提醒开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break;
case CHANGE_TYPE_SERVICE_SWITCH:
if (swEnableService != null) {
swEnableService.setChecked(mTempConfigData.originalBooleanValue);
}
LogUtils.d(TAG, "cancelConfigChange: 服务开关取消恢复值=" + mTempConfigData.originalBooleanValue);
LogUtils.d(TAG, "服务开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break;
case CHANGE_TYPE_CHARGE_SEEKBAR:
if (sbChargeReminder != null) {
@@ -670,7 +733,7 @@ public class MainContentView {
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
tvChargeReminderValue.setText(mTempConfigData.originalIntValue + "%");
}
LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消恢复值=" + mTempConfigData.originalIntValue);
LogUtils.d(TAG, "充电提醒进度取消 | 恢复值=" + mTempConfigData.originalIntValue);
break;
case CHANGE_TYPE_USAGE_SEEKBAR:
if (sbUsageReminder != null) {
@@ -681,10 +744,10 @@ public class MainContentView {
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
tvUsageReminderValue.setText(mTempConfigData.originalIntValue + "%");
}
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒进度取消恢复值=" + mTempConfigData.originalIntValue);
LogUtils.d(TAG, "耗电提醒进度取消 | 恢复值=" + mTempConfigData.originalIntValue);
break;
default:
LogUtils.w(TAG, "cancelConfigChange: 未知变更类型,跳过");
LogUtils.w(TAG, "未知变更类型,跳过");
break;
}
@@ -692,40 +755,11 @@ public class MainContentView {
mTempConfigData = null;
}
// ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
/**
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示,防御空指针)
* @param colorResId 颜色资源 ID
* @return 校准后的颜色值
*/
private int getResourceColor(int colorResId) {
// 空指针防御Context 为空返回默认黑色
if (mContext == null) {
LogUtils.e(TAG, "getResourceColor: Context 为空,返回默认黑色");
return 0xFF000000;
}
// 适配 API30 主题颜色读取
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return mContext.getResources().getColor(colorResId, mContext.getTheme());
} else {
return mContext.getResources().getColor(colorResId);
}
}
/**
* 获取服务启用状态统一从服务控制Bean读取确保全链路状态一致
* @return 服务启用状态true=启用false=禁用)
*/
private boolean getServiceEnableState() {
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
// 本地无配置时,默认禁用服务(与服务初始化逻辑对齐)
return serviceBean != null && serviceBean.isEnableService();
}
/**
* 根据变更类型更新对话框提示语(核心优化:通过 Builder 更新,确保生效)
*/
private void updateDialogMessageByChangeType() {
LogUtils.d(TAG, "updateDialogMessageByChangeType() | mTempConfigData=" + mTempConfigData);
if (mDialogBuilder == null || mTempConfigData == null) return;
String message;
if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) {
@@ -741,13 +775,61 @@ public class MainContentView {
mDialogBuilder.setMessage(message);
}
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
public interface OnViewActionListener {
void onChargeReminderSwitchChanged(boolean isChecked);
void onUsageReminderSwitchChanged(boolean isChecked);
void onServiceSwitchChanged(boolean isChecked);
void onChargeReminderProgressChanged(int progress);
void onUsageReminderProgressChanged(int progress);
// ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
/**
* 实时计算并更新比值预览sbUsageReminder / sbChargeReminder
* 处理除数为0的情况避免崩溃
*/
// private void updateRatioPreview() {
// if (mTvRatioPreview == null) return;
// float ratio;
// // 处理除数为0充电进度为0时显示0可根据需求改为“--”)
// if (mCurrentChargeProgress == 0) {
// ratio = 0.0f;
// } else {
// ratio = (float) mCurrentUsageProgress / mCurrentChargeProgress;
// }
// // 格式化比值保留1位小数适配本地化解决小米手机小数分隔符问题
// String ratioText = String.format(Locale.getDefault(), "比值:%.1f", ratio);
// mTvRatioPreview.setText(ratioText);
// // 触发比值变化回调
// if (mActionListener != null) {
// mActionListener.onRatioChanged(ratio);
// }
// LogUtils.d(TAG, "比值预览更新 | usage=" + mCurrentUsageProgress + " | charge=" + mCurrentChargeProgress + " | ratio=" + ratio);
// }
/**
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示,防御空指针)
* @param colorResId 颜色资源 ID
* @return 校准后的颜色值
*/
private int getResourceColor(int colorResId) {
LogUtils.d(TAG, "getResourceColor() | colorResId=" + colorResId);
// 空指针防御Context 为空返回默认黑色
if (mContext == null) {
LogUtils.e(TAG, "Context 为空,返回默认黑色");
return 0xFF000000;
}
// 适配 API30 主题颜色读取
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return mContext.getResources().getColor(colorResId, mContext.getTheme());
} else {
return mContext.getResources().getColor(colorResId);
}
}
/**
* 获取服务启用状态统一从服务控制Bean读取确保全链路状态一致
* @return 服务启用状态true=启用false=禁用)
*/
private boolean getServiceEnableState() {
LogUtils.d(TAG, "getServiceEnableState()");
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
// 本地无配置时,默认禁用服务(与服务初始化逻辑对齐)
boolean state = serviceBean != null && serviceBean.isEnableService();
LogUtils.d(TAG, "服务启用状态获取完成 | state=" + state);
return state;
}
}

View File

@@ -5,49 +5,19 @@ import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 14:11
* @Describe 垂直进度条控件,适配 API30支持逆时针旋转0在下100在上修复滑块同步+弹窗触发bug
* 新增:实时进度变化监听接口,支持拖动时实时回调进度
*/
public class VerticalSeekBar extends SeekBar {
// ======================== 静态常量 =========================
private static final String TAG = VerticalSeekBar.class.getSimpleName();
// ======================== 成员变量 =========================
private volatile int mProgress = -1; // 当前进度缓存,修复滑块同步问题
private OnVerticalSeekBarTouchListener mTouchListener; // 触摸事件回调接口(核心新增)
// ======================== 构造方法 =========================
public VerticalSeekBar(Context context) {
super(context);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 单参数构造方法初始化完成");
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 双参数构造方法初始化完成");
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 三参数构造方法初始化完成");
}
// ======================== 初始化方法 =========================
private void initView() {
// 移除水平默认阴影,优化垂直显示效果,减少 API30 不必要的绘制开销
setBackgroundDrawable(null);
LogUtils.d(TAG, "initView: 视图初始化完成,移除默认背景阴影");
}
// ======================== 核心接口(新增,用于弹窗触发回调)========================
// ======================== 接口定义(前置,便于外部调用)========================
/**
* 垂直进度条触摸事件回调接口,解决原生 OnSeekBarChangeListener 回调失效问题
* 直接在触摸抬起时回调确保配置变更对话框100%触发
@@ -68,6 +38,67 @@ public class VerticalSeekBar extends SeekBar {
void onTouchCancel(VerticalSeekBar seekBar, int progress);
}
/**
* 垂直进度条实时进度变化监听接口
* 支持拖动过程中实时回调进度用于比值预览等实时UI更新场景
*/
public interface OnVerticalSeekBarChangeListener {
/**
* 进度变化时回调
* @param seekBar 当前垂直进度条实例
* @param progress 当前进度0~100
* @param fromUser 是否是用户触摸导致的进度变化
*/
void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser);
/**
* 开始触摸进度条时回调
* @param seekBar 当前垂直进度条实例
*/
void onStartTrackingTouch(VerticalSeekBar seekBar);
/**
* 停止触摸进度条时回调
* @param seekBar 当前垂直进度条实例
*/
void onStopTrackingTouch(VerticalSeekBar seekBar);
}
// ======================== 成员变量 =========================
// 核心状态当前进度缓存修复滑块同步问题volatile 保证多线程可见性)
private volatile int mProgress = -1;
// 监听接口:触摸事件回调(原有,用于弹窗触发)
private OnVerticalSeekBarTouchListener mTouchListener;
// 监听接口:实时进度变化回调(新增,用于比值计算)
private OnVerticalSeekBarChangeListener mProgressChangeListener;
// ======================== 构造方法 =========================
public VerticalSeekBar(Context context) {
super(context);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context) 初始化");
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context, AttributeSet) 初始化");
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context, AttributeSet, int) 初始化");
}
// ======================== 初始化方法 =========================
private void initView() {
// 移除水平默认阴影,优化垂直显示效果,减少 API30 不必要的绘制开销
setBackgroundDrawable(null);
LogUtils.d(TAG, "initView: 移除默认背景阴影,完成视图初始化");
}
// ======================== 对外设置方法(监听接口绑定)========================
/**
* 设置触摸事件监听器(给外部调用,如 MainContentView 绑定)
* @param listener 触摸事件回调实例
@@ -77,7 +108,16 @@ public class VerticalSeekBar extends SeekBar {
LogUtils.d(TAG, "setOnVerticalSeekBarTouchListener: 触摸监听器绑定完成");
}
// ======================== 重写测量/布局/绘制方法 =========================
/**
* 设置实时进度变化监听器(给外部调用,如 MainContentView 绑定)
* @param listener 实时进度变化回调实例
*/
public void setOnVerticalSeekBarChangeListener(OnVerticalSeekBarChangeListener listener) {
this.mProgressChangeListener = listener;
LogUtils.d(TAG, "setOnVerticalSeekBarChangeListener: 实时进度监听器绑定完成");
}
// ======================== 重写系统方法(测量/布局/绘制)========================
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
@@ -97,51 +137,13 @@ public class VerticalSeekBar extends SeekBar {
canvas.rotate(-90);
canvas.translate(-getHeight(), 0);
super.onDraw(canvas);
LogUtils.v(TAG, "onDraw: 垂直绘制完成,旋转角度=-90°");
LogUtils.v(TAG, "onDraw: 完成垂直绘制,旋转角度=-90°");
}
// ======================== 重写触摸事件(优化事件透传,新增接口回调)========================
@Override
public boolean onTouchEvent(MotionEvent event) {
// 先调用父类方法,保留原生监听器兼容性,同时强制透传事件
super.onTouchEvent(event);
boolean handled = true; // 强制消费事件,避免事件被拦截导致回调丢失
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtils.d(TAG, "onTouchEvent: 触摸按下坐标Y=" + event.getY());
break;
case MotionEvent.ACTION_MOVE:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为=" + mProgress);
break;
case MotionEvent.ACTION_UP:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,触发弹窗回调,进度=" + mProgress);
// 核心:调用新增接口,直接通知外部触发配置变更对话框
if (mTouchListener != null) {
mTouchListener.onTouchUp(this, mProgress);
}
break;
case MotionEvent.ACTION_CANCEL:
LogUtils.d(TAG, "onTouchEvent: 触摸取消,进度保持=" + getProgress());
// 可选:触摸取消时回调,外部可做进度回滚处理
if (mTouchListener != null) {
mTouchListener.onTouchCancel(this, getProgress());
}
break;
}
return handled;
}
// ======================== 重写进度设置方法 =========================
// ======================== 重写进度设置方法(修复滑块同步+新增实时回调)========================
/**
* 重写进度设置,调用尺寸变化方法强制刷新,解决 setProgress 滑块不跟随问题
* 新增:支持外部调用 setProgress 时触发实时进度回调
*/
@Override
public synchronized void setProgress(int progress) {
@@ -149,7 +151,68 @@ public class VerticalSeekBar extends SeekBar {
// 强制触发尺寸变化同步刷新滑块位置核心bug修复逻辑
onSizeChanged(getWidth(), getHeight(), 0, 0);
mProgress = progress;
LogUtils.d(TAG, "setProgress: 进度设置完成,进度=" + progress + ", 滑块同步刷新");
LogUtils.d(TAG, "setProgress: 进度设置" + progress + "滑块同步刷新");
// 触发实时进度监听(外部调用 setProgress 时 fromUser 为 false
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, progress, false);
}
}
// ======================== 重写触摸事件(优化事件透传+实时进度回调)========================
@Override
public boolean onTouchEvent(MotionEvent event) {
// 先调用父类方法,保留原生监听器兼容性,同时强制透传事件
super.onTouchEvent(event);
boolean handled = true; // 强制消费事件,避免事件被拦截导致回调丢失
boolean fromUser = true; // 标记是否是用户触摸导致的进度变化
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtils.d(TAG, "onTouchEvent: 触摸按下Y坐标=" + event.getY());
// 触发实时进度监听:开始触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onStartTrackingTouch(this);
}
break;
case MotionEvent.ACTION_MOVE:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为" + mProgress);
// 触发实时进度监听:进度变化
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, mProgress, fromUser);
}
break;
case MotionEvent.ACTION_UP:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,进度=" + mProgress + ",触发弹窗回调");
// 触发实时进度监听:停止触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, mProgress, fromUser);
mProgressChangeListener.onStopTrackingTouch(this);
}
// 核心:调用原有触摸接口,通知外部触发配置变更对话框
if (mTouchListener != null) {
mTouchListener.onTouchUp(this, mProgress);
}
break;
case MotionEvent.ACTION_CANCEL:
LogUtils.d(TAG, "onTouchEvent: 触摸取消,当前进度=" + getProgress());
// 触发实时进度监听:停止触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onStopTrackingTouch(this);
}
// 可选:触摸取消时回调,外部可做进度回滚处理
if (mTouchListener != null) {
mTouchListener.onTouchCancel(this, getProgress());
}
break;
}
return handled;
}
// ======================== 内部工具方法 =========================
@@ -162,7 +225,7 @@ public class VerticalSeekBar extends SeekBar {
mProgress = getMax() - (int) (getMax() * touchY / getHeight());
// 校准进度范围,防止超出 0~100兼容 API30 进度边界校验)
mProgress = Math.max(0, Math.min(mProgress, getMax()));
LogUtils.v(TAG, "calculateProgress: 进度计算完成,触摸Y=" + touchY + ", 计算进度=" + mProgress);
LogUtils.v(TAG, "calculateProgress: 触摸Y=" + touchY + "计算进度=" + mProgress);
}
}