位图平铺方式调试结束

This commit is contained in:
2025-12-24 19:17:56 +08:00
parent 7d50453e34
commit 558bc16013
9 changed files with 479 additions and 493 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Dec 24 09:10:57 GMT 2025 #Wed Dec 24 11:16:45 GMT 2025
stageCount=29 stageCount=29
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.28 publishVersion=15.14.28
buildCount=57 buildCount=82
baseBetaVersion=15.14.29 baseBetaVersion=15.14.29

View File

@@ -15,6 +15,7 @@ import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
/** /**
* 应用全局入口类适配Android API 30基于Java 7编写 * 应用全局入口类适配Android API 30基于Java 7编写
* 核心策略:极致强制缓存 - 无论内存紧张程度永不自动清理任何缓存Bitmap/视图控件/路径记录) * 核心策略:极致强制缓存 - 无论内存紧张程度永不自动清理任何缓存Bitmap/视图控件/路径记录)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/ */
public class App extends GlobalApplication { public class App extends GlobalApplication {
// ===================== 常量定义区(按功能分类排序) ===================== // ===================== 常量定义区(按功能分类排序) =====================
@@ -35,7 +36,7 @@ public class App extends GlobalApplication {
// ===================== 静态属性区(按工具类优先级排序) ===================== // ===================== 静态属性区(按工具类优先级排序) =====================
// 数据配置工具 // 数据配置工具
private static AppConfigUtils sAppConfigUtils; public static AppConfigUtils sAppConfigUtils;
private static AppCacheUtils sAppCacheUtils; private static AppCacheUtils sAppCacheUtils;
// 全局Bitmap缓存工具极致强制保持一旦初始化永不销毁 // 全局Bitmap缓存工具极致强制保持一旦初始化永不销毁
@@ -56,7 +57,8 @@ public class App extends GlobalApplication {
* 获取应用配置工具实例 * 获取应用配置工具实例
*/ */
public static AppConfigUtils getAppConfigUtils(Context context) { public static AppConfigUtils getAppConfigUtils(Context context) {
LogUtils.d(TAG, "getAppConfigUtils() 调用传入Context类型" + (context != null ? context.getClass().getSimpleName() : "null")); LogUtils.d(TAG, String.format("getAppConfigUtils() 调用 | 传入Context类型=%s",
context != null ? context.getClass().getSimpleName() : "null"));
if (sAppConfigUtils == null) { if (sAppConfigUtils == null) {
sAppConfigUtils = AppConfigUtils.getInstance(context); sAppConfigUtils = AppConfigUtils.getInstance(context);
LogUtils.d(TAG, "getAppConfigUtils()AppConfigUtils实例已初始化"); LogUtils.d(TAG, "getAppConfigUtils()AppConfigUtils实例已初始化");
@@ -68,7 +70,8 @@ public class App extends GlobalApplication {
* 获取应用缓存工具实例 * 获取应用缓存工具实例
*/ */
public static AppCacheUtils getAppCacheUtils(Context context) { public static AppCacheUtils getAppCacheUtils(Context context) {
LogUtils.d(TAG, "getAppCacheUtils() 调用传入Context类型" + (context != null ? context.getClass().getSimpleName() : "null")); LogUtils.d(TAG, String.format("getAppCacheUtils() 调用 | 传入Context类型=%s",
context != null ? context.getClass().getSimpleName() : "null"));
if (sAppCacheUtils == null) { if (sAppCacheUtils == null) {
sAppCacheUtils = AppCacheUtils.getInstance(context); sAppCacheUtils = AppCacheUtils.getInstance(context);
LogUtils.d(TAG, "getAppCacheUtils()AppCacheUtils实例已初始化"); LogUtils.d(TAG, "getAppCacheUtils()AppCacheUtils实例已初始化");
@@ -95,18 +98,18 @@ public class App extends GlobalApplication {
* 极致强制缓存策略下,仅提供手动清理入口,永不自动调用 * 极致强制缓存策略下,仅提供手动清理入口,永不自动调用
*/ */
public static void manualClearAllCache() { public static void manualClearAllCache() {
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 手动清理缓存调用(极致强制缓存策略下,需谨慎使用)"); LogUtils.w(TAG, String.format("%s 手动清理缓存调用(极致强制缓存策略下,需谨慎使用)", CACHE_PROTECT_TAG));
// 清理Bitmap缓存 // 清理Bitmap缓存
if (sBitmapCacheUtils != null) { if (sBitmapCacheUtils != null) {
sBitmapCacheUtils.clearAllCache(); sBitmapCacheUtils.clearAllCache();
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存已手动清理"); LogUtils.d(TAG, String.format("%s Bitmap缓存已手动清理", CACHE_PROTECT_TAG));
} }
// 清理视图控件缓存(仅清除静态引用,不销毁实例) // 清理视图控件缓存(仅清除静态引用,不销毁实例)
if (sMemoryCachedBackgroundView != null) { if (sMemoryCachedBackgroundView != null) {
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件缓存实例保持,仅清除静态引用"); LogUtils.d(TAG, String.format("%s 视图控件缓存实例保持,仅清除静态引用", CACHE_PROTECT_TAG));
sMemoryCachedBackgroundView = null; sMemoryCachedBackgroundView = null;
} }
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 手动清理缓存完成(部分缓存实例仍可能保留在内存中)"); LogUtils.w(TAG, String.format("%s 手动清理缓存完成(部分缓存实例仍可能保留在内存中)", CACHE_PROTECT_TAG));
} }
// ===================== 生命周期方法区(按执行顺序排序) ===================== // ===================== 生命周期方法区(按执行顺序排序) =====================
@@ -117,7 +120,7 @@ public class App extends GlobalApplication {
// 初始化调试模式 // 初始化调试模式
setIsDebugging(BuildConfig.DEBUG); setIsDebugging(BuildConfig.DEBUG);
LogUtils.d(TAG, "onCreate() 调试模式" + BuildConfig.DEBUG); LogUtils.d(TAG, String.format("onCreate() 调试模式=%b", BuildConfig.DEBUG));
// 初始化基础工具 // 初始化基础工具
initBaseTools(); initBaseTools();
@@ -143,7 +146,7 @@ public class App extends GlobalApplication {
releaseReceiver(); releaseReceiver();
// 核心修改:应用终止时也不清理缓存,保持静态实例 // 核心修改:应用终止时也不清理缓存,保持静态实例
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 应用终止,极致强制缓存策略生效,不清理任何缓存"); LogUtils.w(TAG, String.format("%s 应用终止,极致强制缓存策略生效,不清理任何缓存", CACHE_PROTECT_TAG));
LogUtils.d(TAG, "onTerminate() 非缓存资源释放完成,缓存实例保持"); LogUtils.d(TAG, "onTerminate() 非缓存资源释放完成,缓存实例保持");
} }
@@ -152,7 +155,8 @@ public class App extends GlobalApplication {
public void onTrimMemory(int level) { public void onTrimMemory(int level) {
super.onTrimMemory(level); super.onTrimMemory(level);
// 极致强制缓存:禁止任何缓存清理操作,仅记录日志 // 极致强制缓存:禁止任何缓存清理操作,仅记录日志
LogUtils.w(TAG, CACHE_PROTECT_TAG + " onTrimMemory() 调用内存等级level" + level + "极致强制保持所有缓存"); LogUtils.w(TAG, String.format("%s onTrimMemory() 调用 | 内存等级level=%d | 极致强制保持所有缓存",
CACHE_PROTECT_TAG, level));
// 记录详细缓存状态,不执行任何清理 // 记录详细缓存状态,不执行任何清理
logDetailedCacheStatus(); logDetailedCacheStatus();
} }
@@ -161,7 +165,7 @@ public class App extends GlobalApplication {
public void onLowMemory() { public void onLowMemory() {
super.onLowMemory(); super.onLowMemory();
// 极致强制缓存:低内存时也不清理任何缓存 // 极致强制缓存:低内存时也不清理任何缓存
LogUtils.w(TAG, CACHE_PROTECT_TAG + " onLowMemory() 调用极致强制保持所有缓存"); LogUtils.w(TAG, String.format("%s onLowMemory() 调用 | 极致强制保持所有缓存", CACHE_PROTECT_TAG));
// 记录详细缓存状态,不执行任何清理 // 记录详细缓存状态,不执行任何清理
logDetailedCacheStatus(); logDetailedCacheStatus();
} }
@@ -244,21 +248,22 @@ public class App extends GlobalApplication {
LogUtils.d(TAG, "logDetailedCacheStatus() 开始记录详细缓存状态"); LogUtils.d(TAG, "logDetailedCacheStatus() 开始记录详细缓存状态");
// Bitmap缓存状态 // Bitmap缓存状态
if (sBitmapCacheUtils != null) { if (sBitmapCacheUtils != null) {
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存工具实例有效极致强制保持"); LogUtils.d(TAG, String.format("%s Bitmap缓存工具实例有效极致强制保持", CACHE_PROTECT_TAG));
// 假设BitmapCacheUtils有获取缓存数量的方法 // 假设BitmapCacheUtils有获取缓存数量的方法
try { try {
int cacheCount = sBitmapCacheUtils.getCacheCount(); int cacheCount = sBitmapCacheUtils.getCacheCount();
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存数量" + cacheCount); LogUtils.d(TAG, String.format("%s Bitmap缓存数量=%d", CACHE_PROTECT_TAG, cacheCount));
} catch (Exception e) { } catch (Exception e) {
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存数量获取失败不影响缓存异常信息" + e.getMessage()); LogUtils.d(TAG, String.format("%s Bitmap缓存数量获取失败不影响缓存| 异常信息=%s",
CACHE_PROTECT_TAG, e.getMessage()));
} }
} }
// 视图控件缓存状态 // 视图控件缓存状态
if (sMemoryCachedBackgroundView != null) { if (sMemoryCachedBackgroundView != null) {
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件缓存工具实例有效(极致强制保持)"); LogUtils.d(TAG, String.format("%s 视图控件缓存工具实例有效(极致强制保持)", CACHE_PROTECT_TAG));
// 记录视图实例总数 // 记录视图实例总数
int viewInstanceCount = MemoryCachedBackgroundView.getInstanceCount(); int viewInstanceCount = MemoryCachedBackgroundView.getInstanceCount();
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件实例总数" + viewInstanceCount); LogUtils.d(TAG, String.format("%s 视图控件实例总数=%d", CACHE_PROTECT_TAG, viewInstanceCount));
} }
LogUtils.d(TAG, "logDetailedCacheStatus() 详细缓存状态记录完成,所有缓存均极致强制保持"); LogUtils.d(TAG, "logDetailedCacheStatus() 详细缓存状态记录完成,所有缓存均极致强制保持");
} }

View File

@@ -35,11 +35,13 @@ import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.PermissionUtils; import cc.winboll.studio.powerbell.utils.PermissionUtils;
import cc.winboll.studio.powerbell.utils.ServiceUtils; import cc.winboll.studio.powerbell.utils.ServiceUtils;
import cc.winboll.studio.powerbell.views.MainContentView; import cc.winboll.studio.powerbell.views.MainContentView;
import cc.winboll.studio.libappbase.ToastUtils;
/** /**
* 应用核心主活动 * 应用核心主活动
* 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能 * 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能
* 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步 * 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/ */
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener { public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
@@ -87,7 +89,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate() | savedInstanceState=" + savedInstanceState); LogUtils.d(TAG, String.format("onCreate() | savedInstanceState=%s", savedInstanceState));
initGlobalHandler(); initGlobalHandler();
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
@@ -101,7 +103,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onPostCreate(Bundle savedInstanceState) { protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState); super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, "onPostCreate() | savedInstanceState=" + savedInstanceState); LogUtils.d(TAG, String.format("onPostCreate() | savedInstanceState=%s", savedInstanceState));
mPermissionUtils.startPermissionRequest(this); mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 发起权限申请"); LogUtils.d(TAG, "onPostCreate: 发起权限申请");
} }
@@ -113,6 +115,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.resumeADs(this); mADsBannerView.resumeADs(this);
LogUtils.d(TAG, "onResume: 广告视图已恢复");
} }
} }
@@ -131,21 +134,25 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.releaseAdResources(); mADsBannerView.releaseAdResources();
mADsBannerView = null; mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 广告资源已释放");
} }
// 释放核心视图 // 释放核心视图
if (mMainContentView != null) { if (mMainContentView != null) {
mMainContentView.releaseResources(); mMainContentView.releaseResources();
mMainContentView = null; mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
} }
// 销毁Handler防止内存泄漏 // 销毁Handler防止内存泄漏
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null); sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null; sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 全局Handler已销毁");
} }
// 释放Drawable // 释放Drawable
if (mFrameDrawable != null) { if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null); mFrameDrawable.setCallback(null);
mFrameDrawable = null; mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 框架Drawable已释放");
} }
// 置空所有引用 // 置空所有引用
sMainActivity = null; sMainActivity = null;
@@ -162,22 +169,25 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "onActivityResult() | requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data); LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d | data=%s",
requestCode, resultCode, data));
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data); mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
if (requestCode == REQUEST_BACKGROUND_SETTINGS_ACTIVITY && sGlobalHandler != null) { if (requestCode == REQUEST_BACKGROUND_SETTINGS_ACTIVITY && sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 发送背景加载消息");
} }
} }
// ======================== 菜单与导航方法 ======================== // ======================== 菜单与导航方法 ========================
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu() | menu=" + menu); LogUtils.d(TAG, String.format("onCreateOptionsMenu() | menu=%s", menu));
mMenu = menu; mMenu = menu;
AESThemeUtil.inflateMenu(this, menu); AESThemeUtil.inflateMenu(this, menu);
if (App.isDebugging()) { if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu); DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu); getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 已加载测试菜单");
} }
getMenuInflater().inflate(R.menu.toolbar_main, mMenu); getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
return true; return true;
@@ -185,7 +195,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected() | itemId=" + item.getItemId()); LogUtils.d(TAG, String.format("onOptionsItemSelected() | itemId=%d", item.getItemId()));
if (AESThemeUtil.onAppThemeItemSelected(this, item)) { if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate(); recreate();
return true; return true;
@@ -209,7 +219,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
case R.id.action_unittestactivity: case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class)); startActivity(new Intent(this, MainUnitTestActivity.class));
break; break;
case R.id.action_unittest2activity: case R.id.action_unittest2activity:
startActivity(new Intent(this, MainUnitTest2Activity.class)); startActivity(new Intent(this, MainUnitTest2Activity.class));
break; break;
case R.id.action_about: case R.id.action_about:
@@ -227,6 +237,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "setupToolbar()"); LogUtils.d(TAG, "setupToolbar()");
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 已隐藏返回按钮");
} }
} }
@@ -234,11 +245,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
public void onBackPressed() { public void onBackPressed() {
LogUtils.d(TAG, "onBackPressed()"); LogUtils.d(TAG, "onBackPressed()");
moveTaskToBack(true); moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用已退至后台");
} }
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
LogUtils.d(TAG, "dispatchKeyEvent() | event=" + event); LogUtils.d(TAG, String.format("dispatchKeyEvent() | event=%s", event));
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
@@ -246,6 +258,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
private void initPermissionUtils() { private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils()"); LogUtils.d(TAG, "initPermissionUtils()");
mPermissionUtils = PermissionUtils.getInstance(); mPermissionUtils = PermissionUtils.getInstance();
LogUtils.d(TAG, "initPermissionUtils: 权限工具类已初始化");
} }
private void initGlobalHandler() { private void initGlobalHandler() {
@@ -255,10 +268,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) { if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what=" + msg.what); LogUtils.w(TAG, String.format("handleMessage: Activity已销毁跳过消息 | what=%d", msg.what));
return; return;
} }
LogUtils.d(TAG, "handleMessage() | what=" + msg.what); LogUtils.d(TAG, String.format("handleMessage() | what=%d", msg.what));
switch (msg.what) { switch (msg.what) {
case MSG_RELOAD_APPCONFIG: case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData(); sMainActivity.updateViewData();
@@ -266,12 +279,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
case MSG_CURRENTVALUEBATTERY: case MSG_CURRENTVALUEBATTERY:
if (sMainActivity.mMainContentView != null) { if (sMainActivity.mMainContentView != null) {
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1); sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
LogUtils.d(TAG, "handleMessage: 更新当前电量 | value=" + msg.arg1); LogUtils.d(TAG, String.format("handleMessage: 更新当前电量 | value=%d", msg.arg1));
} }
break; break;
case MSG_LOAD_BACKGROUND: case MSG_LOAD_BACKGROUND:
sMainActivity.reloadBackground(); sMainActivity.reloadBackground();
//sMainActivity.setMainLayoutBackgroundColor();
break; break;
case MSG_UPDATE_SERVICE_SWITCH: case MSG_UPDATE_SERVICE_SWITCH:
sMainActivity.updateServiceSwitchUI(); sMainActivity.updateServiceSwitchUI();
@@ -279,6 +291,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
} }
}; };
LogUtils.d(TAG, "initGlobalHandler: 全局Handler已创建");
} else {
LogUtils.d(TAG, "initGlobalHandler: 全局Handler已存在无需重复创建");
} }
} }
@@ -286,6 +301,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "initMainContentView()"); LogUtils.d(TAG, "initMainContentView()");
View rootView = findViewById(android.R.id.content); View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this); mMainContentView = new MainContentView(this, rootView, this);
LogUtils.d(TAG, "initMainContentView: 核心内容视图已初始化");
} }
private void initCriticalView() { private void initCriticalView() {
@@ -295,8 +311,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
if (mToolbar != null) { if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: 工具栏已设置标题样式");
} }
mAdsViewStub = findViewById(R.id.stub_ads_banner); mAdsViewStub = findViewById(R.id.stub_ads_banner);
LogUtils.d(TAG, "initCriticalView: 广告ViewStub已获取");
} }
private void initCoreUtilsAsync() { private void initCoreUtilsAsync() {
@@ -304,7 +322,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动 | threadId=" + Thread.currentThread().getId()); LogUtils.d(TAG, String.format("initCoreUtilsAsync: 异步线程启动 | threadId=%d", Thread.currentThread().getId()));
mApplication = (App) getApplication(); mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext()); mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity()); mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
@@ -314,17 +332,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false); mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置不存在,已创建默认配置");
} }
// 根据配置启停服务 // 根据配置启停服务
final boolean isServiceEnable = mServiceControlBean.isEnableService(); final boolean isServiceEnable = mServiceControlBean.isEnableService();
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName()); final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置状态 | isServiceEnable=" + isServiceEnable + " | isServiceAlive=" + isServiceAlive); LogUtils.d(TAG, String.format("initCoreUtilsAsync: 服务配置状态 | isServiceEnable=%b | isServiceAlive=%b",
isServiceEnable, isServiceAlive));
if (isServiceEnable && !isServiceAlive) { if (isServiceEnable && !isServiceAlive) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
ControlCenterService.startControlCenterService(getApplicationContext()); ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 服务已启动");
} }
}); });
} else if (!isServiceEnable && isServiceAlive) { } else if (!isServiceEnable && isServiceAlive) {
@@ -332,6 +353,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void run() { public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext()); ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 服务已停止");
} }
}); });
} }
@@ -353,6 +375,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
updateViewData(); updateViewData();
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "initCoreUtilsAsync: UI更新消息已发送");
} }
}); });
} }
@@ -360,7 +383,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
private void loadNonCriticalViewDelayed() { private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed() | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms"); LogUtils.d(TAG, String.format("loadNonCriticalViewDelayed() | 延迟时长=%dms", DELAY_LOAD_NON_CRITICAL));
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -383,6 +406,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView == null) { if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate(); View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner); mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: 广告视图已加载");
} else {
LogUtils.d(TAG, "loadAdsView: 广告视图已存在,无需重复加载");
} }
} }
@@ -393,6 +419,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
return; return;
} }
mMainContentView.updateViewData(mFrameDrawable); mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据已更新");
} }
private void reloadBackground() { private void reloadBackground() {
@@ -403,25 +430,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
//ToastUtils.show("currentBgBean");
mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean, true); mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean, true);
LogUtils.d(TAG, "reloadBackground: 已加载自定义背景");
} else { } else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background); mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
LogUtils.d(TAG, "reloadBackground: 已加载默认背景");
} }
} }
// private void setMainLayoutBackgroundColor() {
// LogUtils.d(TAG, "setMainLayoutBackgroundColor()");
// if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
// LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败");
// return;
// }
// BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
// if (currentBgBean != null) {
// mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
// LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局背景色设置完成 | color=" + currentBgBean.getPixelColor2());
// }
// }
private void updateServiceSwitchUI() { private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI()"); LogUtils.d(TAG, "updateServiceSwitchUI()");
if (mMainContentView == null || mServiceControlBean == null) { if (mMainContentView == null || mServiceControlBean == null) {
@@ -432,25 +449,29 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView.setServiceSwitchEnabled(false); mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled); mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true); mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, String.format("updateServiceSwitchUI: 服务开关已更新 | 状态=%b", configEnabled));
} }
// ======================== 服务与线程管理方法 ======================== // ======================== 服务与线程管理方法 ========================
private void toggleServiceEnableState(boolean isEnable) { private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState() | 目标状态=" + isEnable); LogUtils.d(TAG, String.format("toggleServiceEnableState() | 目标状态=%b", isEnable));
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败"); LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return; return;
} }
mServiceControlBean.setIsEnableService(isEnable); mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 服务配置已保存");
// UI开关联动服务启停 // UI开关联动服务启停
if (isEnable) { if (isEnable) {
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) { if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext()); ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动");
} }
} else { } else {
ControlCenterService.stopControlCenterService(getApplicationContext()); ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
} }
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
@@ -463,6 +484,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
APPInfo appInfo = genDefaultAppInfo(); APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo); aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class); WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
LogUtils.d(TAG, "startAboutActivity: 关于页面已启动");
} }
// ======================== 消息发送方法 ======================== // ======================== 消息发送方法 ========================
@@ -470,23 +492,26 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "notifyServiceAppConfigChange()"); LogUtils.d(TAG, "notifyServiceAppConfigChange()");
ControlCenterService.sendAppConfigStatusUpdateMessage(this); ControlCenterService.sendAppConfigStatusUpdateMessage(this);
reloadAppConfig(); reloadAppConfig();
LogUtils.d(TAG, "notifyServiceAppConfigChange: 服务配置已通知更新");
} }
public static void reloadAppConfig() { public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig()"); LogUtils.d(TAG, "reloadAppConfig()");
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG); sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
LogUtils.d(TAG, "reloadAppConfig: 配置重载消息已发送");
} else { } else {
LogUtils.w(TAG, "reloadAppConfig: 全局Handler为空消息发送失败"); LogUtils.w(TAG, "reloadAppConfig: 全局Handler为空消息发送失败");
} }
} }
public static void sendCurrentBatteryValueMessage(int value) { public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage() | 电量=" + value); LogUtils.d(TAG, String.format("sendCurrentBatteryValueMessage() | 电量=%d", value));
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY); Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value; msg.arg1 = value;
sGlobalHandler.sendMessage(msg); sGlobalHandler.sendMessage(msg);
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量消息已发送");
} else { } else {
LogUtils.w(TAG, "sendCurrentBatteryValueMessage: 全局Handler为空消息发送失败"); LogUtils.w(TAG, "sendCurrentBatteryValueMessage: 全局Handler为空消息发送失败");
} }
@@ -507,37 +532,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell"); appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
appInfo.setAppAPKName("PowerBell"); appInfo.setAppAPKName("PowerBell");
appInfo.setAppAPKFolderName("PowerBell"); appInfo.setAppAPKFolderName("PowerBell");
LogUtils.d(TAG, "genDefaultAppInfo: 应用信息已生成");
return appInfo; return appInfo;
} }
// ======================== MainContentView 事件回调 ======================== // ======================== MainContentView 事件回调 ========================
@Override @Override
public void onChargeReminderSwitchChanged(boolean isChecked) { public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged() | isChecked=" + isChecked); LogUtils.d(TAG, String.format("onChargeReminderSwitchChanged() | isChecked=%b", isChecked));
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderSwitchChanged(boolean isChecked) { public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged() | isChecked=" + isChecked); LogUtils.d(TAG, String.format("onUsageReminderSwitchChanged() | isChecked=%b", isChecked));
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onServiceSwitchChanged(boolean isChecked) { public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged() | isChecked=" + isChecked); LogUtils.d(TAG, String.format("onServiceSwitchChanged() | isChecked=%b", isChecked));
toggleServiceEnableState(isChecked); toggleServiceEnableState(isChecked);
} }
@Override @Override
public void onChargeReminderProgressChanged(int progress) { public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged() | progress=" + progress); LogUtils.d(TAG, String.format("onChargeReminderProgressChanged() | progress=%d", progress));
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderProgressChanged(int progress) { public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged() | progress=" + progress); LogUtils.d(TAG, String.format("onUsageReminderProgressChanged() | progress=%d", progress));
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
} }

View File

@@ -29,6 +29,7 @@ import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
import cc.winboll.studio.powerbell.dialogs.ColorPaletteDialog; import cc.winboll.studio.powerbell.dialogs.ColorPaletteDialog;
import cc.winboll.studio.powerbell.dialogs.NetworkBackgroundDialog; import cc.winboll.studio.powerbell.dialogs.NetworkBackgroundDialog;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils; import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
import cc.winboll.studio.powerbell.utils.FileUtils; import cc.winboll.studio.powerbell.utils.FileUtils;
@@ -38,6 +39,11 @@ import cc.winboll.studio.powerbell.utils.UriUtils;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
import java.io.File; import java.io.File;
/**
* 背景设置页面(支持图片选择、拍照、裁剪、像素拾取、调色板等功能)
* 核心:基于强制缓存策略,支持预览与设置提交分离,保留操作状态
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class BackgroundSettingsActivity extends WinBoLLActivity { public class BackgroundSettingsActivity extends WinBoLLActivity {
// ====================== 常量定义(按功能分类置顶)====================== // ====================== 常量定义(按功能分类置顶)======================
@@ -79,7 +85,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
LogUtils.d(TAG, "生命周期onCreate 开始初始化"); LogUtils.d(TAG, "生命周期 onCreate 开始初始化");
setContentView(R.layout.activity_background_settings); setContentView(R.layout.activity_background_settings);
// 初始化核心组件 // 初始化核心组件
@@ -87,44 +93,44 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
// 初始化界面与事件 // 初始化界面与事件
initToolbar(); initToolbar();
initClickListeners(); initClickListeners();
LogUtils.d(TAG, "初始化界面与事件绑定完成"); LogUtils.d(TAG, "初始化 界面与事件绑定完成");
// 处理分享意图或初始化预览 // 处理分享意图或初始化预览
handleIntentOrPreview(); handleIntentOrPreview();
// 初始化预览环境并刷新 // 初始化预览环境并刷新
initPreviewEnvironment(); initPreviewEnvironment();
LogUtils.d(TAG, "生命周期onCreate 初始化完成"); LogUtils.d(TAG, "生命周期 onCreate 初始化完成");
} }
@Override @Override
protected void onPostCreate(Bundle savedInstanceState) { protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState); super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, "生命周期onPostCreate 执行双重刷新预览"); LogUtils.d(TAG, "生命周期 onPostCreate 执行双重刷新预览");
doubleRefreshPreview(); doubleRefreshPreview();
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "回调触发requestCode" + requestCode + "resultCode" + resultCode); LogUtils.d(TAG, String.format("回调触发 requestCode=%dresultCode=%d", requestCode, resultCode));
try { try {
if (resultCode != RESULT_OK) { if (resultCode != RESULT_OK) {
LogUtils.d(TAG, "回调处理结果非RESULT_OK执行取消逻辑"); LogUtils.d(TAG, "回调处理 结果非RESULT_OK执行取消逻辑");
handleOperationCancelOrFail(); handleOperationCancelOrFail();
return; return;
} }
handleActivityResult(requestCode, data); handleActivityResult(requestCode, data);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "回调异常requestCode" + requestCode + ",异常信息:" + e.getMessage()); LogUtils.e(TAG, String.format("回调异常 requestCode=%d异常信息=%s", requestCode, e.getMessage()));
ToastUtils.show("操作失败"); ToastUtils.show("操作失败");
} }
} }
@Override @Override
public void finish() { public void finish() {
LogUtils.d(TAG, "生命周期finish 触发isCommitSettings" + isCommitSettings + "isPreviewBackgroundChanged" + isPreviewBackgroundChanged); LogUtils.d(TAG, String.format("生命周期 finish 触发isCommitSettings=%bisPreviewBackgroundChanged=%b", isCommitSettings, isPreviewBackgroundChanged));
if (isCommitSettings) { if (isCommitSettings) {
super.finish(); super.finish();
} else { } else {
@@ -136,7 +142,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
LogUtils.d(TAG, "权限回调requestCode" + requestCode + ",权限数量:" + permissions.length); LogUtils.d(TAG, String.format("权限回调 requestCode=%d权限数量=%d", requestCode, permissions.length));
if (requestCode == REQUEST_CAMERA_PERMISSION) { if (requestCode == REQUEST_CAMERA_PERMISSION) {
handleCameraPermissionResult(grantResults); handleCameraPermissionResult(grantResults);
} }
@@ -146,7 +152,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private void initToolbar() { private void initToolbar() {
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
if (mToolbar == null) { if (mToolbar == null) {
LogUtils.e(TAG, "初始化异常Toolbar未找到"); LogUtils.e(TAG, "初始化异常 Toolbar未找到");
return; return;
} }
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
@@ -156,15 +162,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
mToolbar.setNavigationOnClickListener(new View.OnClickListener() { mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "导航栏点击返回按钮"); LogUtils.d(TAG, "导航栏 点击返回按钮");
finish(); finish();
} }
}); });
LogUtils.d(TAG, "界面初始化Toolbar 配置完成"); LogUtils.d(TAG, "界面初始化 Toolbar 配置完成");
} }
private void initClickListeners() { private void initClickListeners() {
LogUtils.d(TAG, "界面初始化开始绑定按钮点击事件"); LogUtils.d(TAG, "界面初始化 开始绑定按钮点击事件");
// 绑定所有按钮点击事件 // 绑定所有按钮点击事件
bindClickListener(R.id.activitybackgroundsettingsAButton1, onOriginNullClickListener); bindClickListener(R.id.activitybackgroundsettingsAButton1, onOriginNullClickListener);
bindClickListener(R.id.activitybackgroundsettingsAButton2, onReceivedPictureClickListener); bindClickListener(R.id.activitybackgroundsettingsAButton2, onReceivedPictureClickListener);
@@ -176,7 +182,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
bindClickListener(R.id.activitybackgroundsettingsAButton8, onPixelPickerClickListener); bindClickListener(R.id.activitybackgroundsettingsAButton8, onPixelPickerClickListener);
bindClickListener(R.id.activitybackgroundsettingsAButton9, onColorPaletteClickListener); bindClickListener(R.id.activitybackgroundsettingsAButton9, onColorPaletteClickListener);
bindClickListener(R.id.activitybackgroundsettingsAButton10, onCleanPixelClickListener); bindClickListener(R.id.activitybackgroundsettingsAButton10, onCleanPixelClickListener);
LogUtils.d(TAG, "界面初始化按钮点击事件绑定完成"); LogUtils.d(TAG, "界面初始化 按钮点击事件绑定完成");
} }
// 通用按钮绑定工具方法 // 通用按钮绑定工具方法
@@ -185,7 +191,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
if (view != null) { if (view != null) {
view.setOnClickListener(listener); view.setOnClickListener(listener);
} else { } else {
LogUtils.e(TAG, "绑定异常未找到视图:" + resId); LogUtils.e(TAG, String.format("绑定异常 未找到视图:%d", resId));
} }
} }
@@ -193,10 +199,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() { private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击取消背景图片"); LogUtils.d(TAG, "按钮点击 取消背景图片");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "操作异常预览Bean为空"); LogUtils.e(TAG, "操作异常 预览Bean为空");
return; return;
} }
previewBean.setIsUseBackgroundFile(false); previewBean.setIsUseBackgroundFile(false);
@@ -209,15 +215,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onSelectPictureClickListener = new View.OnClickListener() { private View.OnClickListener onSelectPictureClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击选择图片"); LogUtils.d(TAG, "按钮点击 选择图片");
launchImageSelector(); launchImageSelector();
} }
}; };
private View.OnClickListener onNetworkBackgroundDialog = new View.OnClickListener() { private View.OnClickListener onNetworkBackgroundDialog = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
NetworkBackgroundDialog networkBackgroundDialog = new NetworkBackgroundDialog(BackgroundSettingsActivity.this, new NetworkBackgroundDialog.OnDialogClickListener(){ NetworkBackgroundDialog networkBackgroundDialog = new NetworkBackgroundDialog(BackgroundSettingsActivity.this, new NetworkBackgroundDialog.OnDialogClickListener() {
@Override @Override
public void onConfirm(String szConfirmFilePath) { public void onConfirm(String szConfirmFilePath) {
// 拷贝文件到预览数据并启动裁剪 // 拷贝文件到预览数据并启动裁剪
@@ -230,14 +236,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
public void onCancel() { public void onCancel() {
} }
}); });
networkBackgroundDialog.show(); networkBackgroundDialog.show();
} }
}; };
private View.OnClickListener onCropPictureClickListener = new View.OnClickListener() { private View.OnClickListener onCropPictureClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击固定比例裁剪"); LogUtils.d(TAG, "按钮点击 固定比例裁剪");
startImageCrop(false); startImageCrop(false);
} }
}; };
@@ -245,7 +251,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onCropFreePictureClickListener = new View.OnClickListener() { private View.OnClickListener onCropFreePictureClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击自由裁剪"); LogUtils.d(TAG, "按钮点击 自由裁剪");
startImageCrop(true); startImageCrop(true);
} }
}; };
@@ -253,11 +259,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onTakePhotoClickListener = new View.OnClickListener() { private View.OnClickListener onTakePhotoClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击拍照"); LogUtils.d(TAG, "按钮点击 拍照");
// 动态申请相机权限 // 动态申请相机权限
if (ContextCompat.checkSelfPermission(BackgroundSettingsActivity.this, Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(BackgroundSettingsActivity.this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
LogUtils.d(TAG, "拍照准备相机权限未授予,发起申请"); LogUtils.d(TAG, "拍照准备 相机权限未授予,发起申请");
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(
BackgroundSettingsActivity.this, BackgroundSettingsActivity.this,
new String[]{Manifest.permission.CAMERA}, new String[]{Manifest.permission.CAMERA},
@@ -271,10 +277,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() { private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击恢复收到的图片"); LogUtils.d(TAG, "按钮点击 恢复收到的图片");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "操作异常预览Bean为空"); LogUtils.e(TAG, "操作异常 预览Bean为空");
return; return;
} }
previewBean.setIsUseBackgroundFile(true); previewBean.setIsUseBackgroundFile(true);
@@ -287,10 +293,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() { private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击像素拾取"); LogUtils.d(TAG, "按钮点击 像素拾取");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "操作异常预览Bean为空"); LogUtils.e(TAG, "操作异常 预览Bean为空");
ToastUtils.show("无有效图片可拾取像素"); ToastUtils.show("无有效图片可拾取像素");
return; return;
} }
@@ -298,23 +304,23 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
File targetFile = new File(targetImagePath); File targetFile = new File(targetImagePath);
if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) { if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) {
ToastUtils.show("无有效图片可拾取像素"); ToastUtils.show("无有效图片可拾取像素");
LogUtils.e(TAG, "像素拾取失败文件无效:" + targetImagePath); LogUtils.e(TAG, String.format("像素拾取失败 文件无效:%s", targetImagePath));
return; return;
} }
Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class); Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class);
intent.putExtra("imagePath", targetImagePath); intent.putExtra("imagePath", targetImagePath);
startActivityForResult(intent, REQUEST_PIXELPICKER); startActivityForResult(intent, REQUEST_PIXELPICKER);
LogUtils.d(TAG, "像素拾取启动路径:" + targetImagePath); LogUtils.d(TAG, String.format("像素拾取启动 路径:%s", targetImagePath));
} }
}; };
private View.OnClickListener onCleanPixelClickListener = new View.OnClickListener() { private View.OnClickListener onCleanPixelClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击清空像素颜色"); LogUtils.d(TAG, "按钮点击 清空像素颜色");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "操作异常预览Bean为空"); LogUtils.e(TAG, "操作异常 预览Bean为空");
return; return;
} }
int oldColor = previewBean.getPixelColor(); int oldColor = previewBean.getPixelColor();
@@ -323,21 +329,21 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
doubleRefreshPreview(); doubleRefreshPreview();
isPreviewBackgroundChanged = true; isPreviewBackgroundChanged = true;
ToastUtils.show("像素颜色已清空"); ToastUtils.show("像素颜色已清空");
LogUtils.d(TAG, "【像素清空】旧颜色:" + String.format("#%08X", oldColor)); LogUtils.d(TAG, String.format("像素清空 旧颜色:#%08X", oldColor));
} }
}; };
private View.OnClickListener onColorPaletteClickListener = new View.OnClickListener() { private View.OnClickListener onColorPaletteClickListener = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "按钮点击调色板按钮"); LogUtils.d(TAG, "按钮点击 调色板按钮");
final BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); final BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "操作异常预览Bean为空"); LogUtils.e(TAG, "操作异常 预览Bean为空");
return; return;
} }
int initialColor = previewBean.getPixelColor(); int initialColor = previewBean.getPixelColor();
LogUtils.d(TAG, "【调色板】初始颜色:" + String.format("#%08X", initialColor)); LogUtils.d(TAG, String.format("调色板 初始颜色:#%08X", initialColor));
ColorPaletteDialog dialog = new ColorPaletteDialog(BackgroundSettingsActivity.this, initialColor, new ColorPaletteDialog.OnColorSelectedListener() { ColorPaletteDialog dialog = new ColorPaletteDialog(BackgroundSettingsActivity.this, initialColor, new ColorPaletteDialog.OnColorSelectedListener() {
@Override @Override
public void onColorSelected(int color) { public void onColorSelected(int color) {
@@ -345,11 +351,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
mBgSourceUtils.saveSettings(); mBgSourceUtils.saveSettings();
doubleRefreshPreview(); doubleRefreshPreview();
isPreviewBackgroundChanged = true; isPreviewBackgroundChanged = true;
LogUtils.d(TAG, "【颜色选择】选中颜色:" + String.format("#%08X", color)); LogUtils.d(TAG, String.format("颜色选择 选中颜色:#%08X", color));
} }
}); });
dialog.show(); dialog.show();
LogUtils.d(TAG, "调色板对话框已显示"); LogUtils.d(TAG, "调色板 对话框已显示");
} }
}; };
@@ -360,9 +366,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @return 适配后的Uri失败返回null * @return 适配后的Uri失败返回null
*/ */
public Uri getFileProviderUri(File file) { public Uri getFileProviderUri(File file) {
LogUtils.d(TAG, "工具方法生成FileProvider Uri文件路径" + (file != null ? file.getAbsolutePath() : "null")); LogUtils.d(TAG, String.format("工具方法 生成FileProvider Uri文件路径%s", (file != null ? file.getAbsolutePath() : "null")));
if (file == null) { if (file == null) {
LogUtils.e(TAG, "工具异常文件为空"); LogUtils.e(TAG, "工具异常 文件为空");
return null; return null;
} }
try { try {
@@ -373,7 +379,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
return Uri.fromFile(file); return Uri.fromFile(file);
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "工具异常生成Uri失败" + e.getMessage()); LogUtils.e(TAG, String.format("工具异常 生成Uri失败%s", e.getMessage()));
return null; return null;
} }
} }
@@ -385,7 +391,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
*/ */
private boolean isBitmapValid(Bitmap bitmap) { private boolean isBitmapValid(Bitmap bitmap) {
boolean isValid = bitmap != null && !bitmap.isRecycled(); boolean isValid = bitmap != null && !bitmap.isRecycled();
LogUtils.d(TAG, "工具方法Bitmap有效性校验" + isValid); LogUtils.d(TAG, String.format("工具方法 Bitmap有效性校验%b", isValid));
return isValid; return isValid;
} }
@@ -393,9 +399,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* 双重刷新预览,确保背景加载最新数据 * 双重刷新预览,确保背景加载最新数据
*/ */
private void doubleRefreshPreview() { private void doubleRefreshPreview() {
LogUtils.d(TAG, "工具方法开始双重刷新预览"); LogUtils.d(TAG, "工具方法 开始双重刷新预览");
if (mBgSourceUtils == null || mBackgroundView == null || isFinishing()) { if (mBgSourceUtils == null || mBackgroundView == null || isFinishing()) {
LogUtils.w(TAG, "双重刷新跳过对象为空或Activity已结束"); LogUtils.w(TAG, "双重刷新 跳过对象为空或Activity已结束");
return; return;
} }
@@ -404,10 +410,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
mBackgroundView.loadByBackgroundBean(previewBean, true); mBackgroundView.loadByBackgroundBean(previewBean, true);
//mBackgroundView.setBackgroundColor(previewBean.getPixelColor()); LogUtils.d(TAG, "双重刷新 第一重完成");
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "双重刷新第一重异常:" + e.getMessage()); LogUtils.e(TAG, String.format("双重刷新 第一重异常:%s", e.getMessage()));
return; return;
} }
@@ -420,10 +425,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
mBackgroundView.loadByBackgroundBean(previewBean, true); mBackgroundView.loadByBackgroundBean(previewBean, true);
//mBackgroundView.setBackgroundColor(previewBean.getPixelColor()); LogUtils.d(TAG, "双重刷新 第二重完成");
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "双重刷新第二重异常:" + e.getMessage()); LogUtils.e(TAG, String.format("双重刷新 第二重异常:%s", e.getMessage()));
} }
} }
} }
@@ -438,13 +442,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
// 初始化视图 // 初始化视图
mBackgroundView = findViewById(R.id.background_view); mBackgroundView = findViewById(R.id.background_view);
if (mBackgroundView == null) { if (mBackgroundView == null) {
LogUtils.e(TAG, "初始化异常BackgroundView未找到"); LogUtils.e(TAG, "初始化异常 BackgroundView未找到");
} }
// 初始化工具类 // 初始化工具类
mBgSourceUtils = BackgroundSourceUtils.getInstance(this); mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
mBitmapCache = BitmapCacheUtils.getInstance(); mBitmapCache = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "初始化视图与工具类加载完成"); LogUtils.d(TAG, "初始化 视图与工具类加载完成");
} }
/** /**
@@ -455,7 +459,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
ToastUtils.show("已接收分享图片"); ToastUtils.show("已接收分享图片");
} else { } else {
mBgSourceUtils.setCurrentSourceToPreview(); mBgSourceUtils.setCurrentSourceToPreview();
LogUtils.d(TAG, "预览初始化加载当前背景配置"); LogUtils.d(TAG, "预览初始化 加载当前背景配置");
} }
} }
@@ -477,7 +481,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
if (intent != null) { if (intent != null) {
String action = intent.getAction(); String action = intent.getAction();
String type = intent.getType(); String type = intent.getType();
LogUtils.d(TAG, "分享处理action" + action + "type" + type); LogUtils.d(TAG, String.format("分享处理 action%stype%s", action, type));
if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) { if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) {
showSharePreviewDialog(); showSharePreviewDialog();
return true; return true;
@@ -490,7 +494,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* 显示分享图片预览对话框 * 显示分享图片预览对话框
*/ */
private void showSharePreviewDialog() { private void showSharePreviewDialog() {
LogUtils.d(TAG, "showSharePreviewDialog()"); LogUtils.d(TAG, "showSharePreviewDialog()");
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener() { BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener() {
@Override @Override
public void onAcceptRecivedPicture(Uri uriRecivedPicture) { public void onAcceptRecivedPicture(Uri uriRecivedPicture) {
@@ -500,7 +504,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
} }
}); });
dlg.show(); dlg.show();
LogUtils.d(TAG, "分享处理显示图片预览对话框"); LogUtils.d(TAG, "分享处理 显示图片预览对话框");
} }
/** /**
@@ -509,19 +513,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @return 是图片返回true否则false * @return 是图片返回true否则false
*/ */
private boolean isImageType(String mimeType) { private boolean isImageType(String mimeType) {
if (mimeType == null) { if (mimeType == null) {
return false; return false;
} }
String lowerMimeType = mimeType.toLowerCase(); String lowerMimeType = mimeType.toLowerCase();
LogUtils.d("isImageType", "mimeType: " + mimeType + ", lowerMimeType: " + lowerMimeType); LogUtils.d("isImageType", String.format("mimeType: %s, lowerMimeType: %s", mimeType, lowerMimeType));
return lowerMimeType.startsWith("image/"); return lowerMimeType.startsWith("image/");
} }
/** /**
* 启动图片选择器 * 启动图片选择器
*/ */
private void launchImageSelector() { private void launchImageSelector() {
LogUtils.d(TAG, "业务逻辑启动图片选择器"); LogUtils.d(TAG, "业务逻辑 启动图片选择器");
Intent[] intents = createImageSelectorIntents(); Intent[] intents = createImageSelectorIntents();
Intent validIntent = findValidIntent(intents); Intent validIntent = findValidIntent(intents);
@@ -584,14 +588,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
Intent chooser = Intent.createChooser(validIntent, "选择图片"); Intent chooser = Intent.createChooser(validIntent, "选择图片");
chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(chooser, REQUEST_SELECT_PICTURE); startActivityForResult(chooser, REQUEST_SELECT_PICTURE);
LogUtils.d(TAG, "选图意图启动图片选择"); LogUtils.d(TAG, "选图意图 启动图片选择");
} }
/** /**
* 显示无相册应用提示对话框 * 显示无相册应用提示对话框
*/ */
private void showNoGalleryDialog() { private void showNoGalleryDialog() {
LogUtils.d(TAG, "选图意图无相册应用"); LogUtils.d(TAG, "选图意图 无相册应用");
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -629,7 +633,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
*/ */
private void handleOperationCancelOrFail() { private void handleOperationCancelOrFail() {
mBgSourceUtils.setCurrentSourceToPreview(); mBgSourceUtils.setCurrentSourceToPreview();
LogUtils.d(TAG, "业务逻辑操作取消或失败,恢复预览"); LogUtils.d(TAG, "业务逻辑 操作取消或失败,恢复预览");
ToastUtils.show("操作取消或失败"); ToastUtils.show("操作取消或失败");
doubleRefreshPreview(); doubleRefreshPreview();
} }
@@ -638,10 +642,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* 处理拍照逻辑(权限通过后执行) * 处理拍照逻辑(权限通过后执行)
*/ */
void handleTakePhoto() { void handleTakePhoto() {
LogUtils.d(TAG, "业务逻辑开始处理拍照"); LogUtils.d(TAG, "业务逻辑 开始处理拍照");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "拍照失败预览Bean为空"); LogUtils.e(TAG, "拍照失败 预览Bean为空");
ToastUtils.show("拍照文件创建失败"); ToastUtils.show("拍照文件创建失败");
return; return;
} }
@@ -649,7 +653,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
File takePhotoFile = new File(previewBean.getBackgroundFilePath()); File takePhotoFile = new File(previewBean.getBackgroundFilePath());
if (!takePhotoFile.exists()) { if (!takePhotoFile.exists()) {
ToastUtils.show("拍照文件创建失败"); ToastUtils.show("拍照文件创建失败");
LogUtils.e(TAG, "拍照失败文件不存在:" + takePhotoFile.getAbsolutePath()); LogUtils.e(TAG, String.format("拍照失败 文件不存在:%s", takePhotoFile.getAbsolutePath()));
return; return;
} }
@@ -661,11 +665,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
} }
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
LogUtils.d(TAG, "拍照启动Uri" + photoUri.toString()); LogUtils.d(TAG, String.format("拍照启动 Uri%s", photoUri.toString()));
} catch (Exception e) { } catch (Exception e) {
String errMsg = "拍照启动异常:" + e.getMessage(); String errMsg = "拍照启动异常:" + e.getMessage();
ToastUtils.show(errMsg.substring(0, 20)); ToastUtils.show(errMsg.substring(0, 20));
LogUtils.e(TAG, "拍照失败" + e.getMessage()); LogUtils.e(TAG, String.format("拍照失败 %s", e.getMessage()));
} }
} }
@@ -689,7 +693,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
handlePixelPickerResult(); handlePixelPickerResult();
break; break;
default: default:
LogUtils.d(TAG, "回调忽略未知requestCode" + requestCode); LogUtils.d(TAG, String.format("回调忽略 未知requestCode%d", requestCode));
break; break;
} }
} }
@@ -699,10 +703,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @param data 回调数据 * @param data 回调数据
*/ */
private void handleTakePhotoResult(Intent data) { private void handleTakePhotoResult(Intent data) {
LogUtils.d(TAG, "业务逻辑处理拍照结果"); LogUtils.d(TAG, "业务逻辑 处理拍照结果");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "拍照结果处理预览Bean为空"); LogUtils.e(TAG, "拍照结果处理 预览Bean为空");
return; return;
} }
@@ -712,7 +716,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
doubleRefreshPreview(); doubleRefreshPreview();
startImageCrop(false); startImageCrop(false);
LogUtils.d(TAG, "拍照完成已启动裁剪"); LogUtils.d(TAG, "拍照完成 已启动裁剪");
} }
/** /**
@@ -720,30 +724,30 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @param data 回调数据 * @param data 回调数据
*/ */
private void handleSelectPictureResult(Intent data) { private void handleSelectPictureResult(Intent data) {
LogUtils.d(TAG, "业务逻辑处理选图结果"); LogUtils.d(TAG, "业务逻辑 处理选图结果");
Uri selectedImage = data.getData(); Uri selectedImage = data.getData();
if (selectedImage == null) { if (selectedImage == null) {
ToastUtils.show("图片Uri为空"); ToastUtils.show("图片Uri为空");
LogUtils.e(TAG, "选图结果Uri为空"); LogUtils.e(TAG, "选图结果 Uri为空");
return; return;
} }
LogUtils.d(TAG, "选图回调系统返回Uri : " + selectedImage.toString()); LogUtils.d(TAG, String.format("选图回调 系统返回Uri : %s", selectedImage.toString()));
// 申请持久化权限API33+ // 申请持久化权限API33+
if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) { if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) {
getContentResolver().takePersistableUriPermission( getContentResolver().takePersistableUriPermission(
selectedImage, selectedImage,
Intent.FLAG_GRANT_READ_URI_PERMISSION); Intent.FLAG_GRANT_READ_URI_PERMISSION);
LogUtils.d(TAG, "选图权限已添加持久化权限"); LogUtils.d(TAG, "选图权限 已添加持久化权限");
} }
// 同步文件并启动裁剪 // 同步文件并启动裁剪
if (putUriFileToPreviewSource(selectedImage)) { if (putUriFileToPreviewSource(selectedImage)) {
LogUtils.d(TAG, "选图同步路径绑定完成"); LogUtils.d(TAG, "选图同步 路径绑定完成");
startImageCrop(false); startImageCrop(false);
} else { } else {
ToastUtils.show("图片同步失败"); ToastUtils.show("图片同步失败");
LogUtils.e(TAG, "选图同步文件复制失败"); LogUtils.e(TAG, "选图同步 文件复制失败");
} }
} }
@@ -755,7 +759,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private boolean putUriFileToPreviewSource(Uri srcUriFile) { private boolean putUriFileToPreviewSource(Uri srcUriFile) {
String filePath = UriUtils.getFilePathFromUri(this, srcUriFile); String filePath = UriUtils.getFilePathFromUri(this, srcUriFile);
if (TextUtils.isEmpty(filePath)) { if (TextUtils.isEmpty(filePath)) {
LogUtils.e(TAG, "选图同步Uri解析路径为空"); LogUtils.e(TAG, "选图同步 Uri解析路径为空");
return false; return false;
} }
File srcFile = new File(filePath); File srcFile = new File(filePath);
@@ -768,16 +772,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @return 同步成功返回true否则false * @return 同步成功返回true否则false
*/ */
private boolean putUriFileToPreviewSource(File srcFile) { private boolean putUriFileToPreviewSource(File srcFile) {
LogUtils.d(TAG, "选图同步源文件:" + srcFile.getAbsolutePath()); LogUtils.d(TAG, String.format("选图同步 源文件:%s", srcFile.getAbsolutePath()));
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
File dstFile = new File(previewBean.getBackgroundFilePath()); File dstFile = new File(previewBean.getBackgroundFilePath());
LogUtils.d(TAG, "选图同步目标文件:" + dstFile.getAbsolutePath()); LogUtils.d(TAG, String.format("选图同步 目标文件:%s", dstFile.getAbsolutePath()));
if (FileUtils.copyFile(srcFile, dstFile)) { if (FileUtils.copyFile(srcFile, dstFile)) {
LogUtils.d(TAG, "选图同步文件拷贝成功"); LogUtils.d(TAG, "选图同步 文件拷贝成功");
return true; return true;
} }
LogUtils.d(TAG, "选图同步文件无法拷贝"); LogUtils.d(TAG, "选图同步 文件无法拷贝");
return false; return false;
} }
@@ -786,10 +790,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @param data 回调数据 * @param data 回调数据
*/ */
private void handleCropImageResult(Intent data) { private void handleCropImageResult(Intent data) {
LogUtils.d(TAG, "业务逻辑处理裁剪结果"); LogUtils.d(TAG, "业务逻辑 处理裁剪结果");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "裁剪结果处理预览Bean为空"); LogUtils.e(TAG, "裁剪结果处理 预览Bean为空");
handleOperationCancelOrFail(); handleOperationCancelOrFail();
return; return;
} }
@@ -814,11 +818,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
*/ */
private void handleCropSuccess(BackgroundBean previewBean, long fileSize) { private void handleCropSuccess(BackgroundBean previewBean, long fileSize) {
isPreviewBackgroundChanged = true; isPreviewBackgroundChanged = true;
LogUtils.d(TAG, "裁剪结果裁剪成功,文件大小:" + fileSize); LogUtils.d(TAG, String.format("裁剪结果 裁剪成功,文件大小:%d", fileSize));
previewBean.setIsUseBackgroundFile(true); previewBean.setIsUseBackgroundFile(true);
previewBean.setIsUseBackgroundScaledCompressFile(true); previewBean.setIsUseBackgroundScaledCompressFile(true);
mBgSourceUtils.saveSettings(); mBgSourceUtils.saveSettings();
doubleRefreshPreview(); doubleRefreshPreview();
} }
/** /**
@@ -829,14 +833,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
*/ */
private void handleCropFailure(boolean isFileExist, boolean isFileReadable, long fileSize) { private void handleCropFailure(boolean isFileExist, boolean isFileReadable, long fileSize) {
handleOperationCancelOrFail(); handleOperationCancelOrFail();
LogUtils.e(TAG, "裁剪结果裁剪失败,文件状态:存在=" + isFileExist + ",可读=" + isFileReadable + ",大小=" + fileSize); LogUtils.e(TAG, String.format("裁剪结果 裁剪失败,文件状态:存在=%b可读=%b大小=%d", isFileExist, isFileReadable, fileSize));
} }
/** /**
* 处理像素拾取结果 * 处理像素拾取结果
*/ */
private void handlePixelPickerResult() { private void handlePixelPickerResult() {
LogUtils.d(TAG, "业务逻辑处理像素拾取结果"); LogUtils.d(TAG, "业务逻辑 处理像素拾取结果");
doubleRefreshPreview(); doubleRefreshPreview();
isPreviewBackgroundChanged = true; isPreviewBackgroundChanged = true;
} }
@@ -847,10 +851,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
*/ */
private void handleCameraPermissionResult(int[] grantResults) { private void handleCameraPermissionResult(int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LogUtils.d(TAG, "权限申请相机权限授予成功"); LogUtils.d(TAG, "权限申请 相机权限授予成功");
handleTakePhoto(); handleTakePhoto();
} else { } else {
LogUtils.d(TAG, "权限申请相机权限授予失败"); LogUtils.d(TAG, "权限申请 相机权限授予失败");
ToastUtils.show("相机权限被拒绝,无法拍照"); ToastUtils.show("相机权限被拒绝,无法拍照");
// 引导用户到设置页面开启权限(用户选择不再询问时) // 引导用户到设置页面开启权限(用户选择不再询问时)
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
@@ -868,7 +872,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
intent.setData(uri); intent.setData(uri);
startActivity(intent); startActivity(intent);
ToastUtils.show("请在设置中开启相机权限"); ToastUtils.show("请在设置中开启相机权限");
LogUtils.d(TAG, "权限引导启动应用设置页面"); LogUtils.d(TAG, "权限引导 启动应用设置页面");
} }
/** /**
@@ -903,7 +907,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
private void startImageCrop(boolean isFreeCrop) { private void startImageCrop(boolean isFreeCrop) {
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean == null) { if (previewBean == null) {
LogUtils.e(TAG, "裁剪启动预览Bean为空"); LogUtils.e(TAG, "裁剪启动 预览Bean为空");
ToastUtils.show("裁剪失败:无有效图片"); ToastUtils.show("裁剪失败:无有效图片");
return; return;
} }
@@ -915,7 +919,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
height, height,
isFreeCrop, isFreeCrop,
REQUEST_CROP_IMAGE); REQUEST_CROP_IMAGE);
LogUtils.d(TAG, "裁剪启动是否自由裁剪:" + isFreeCrop + ",目标尺寸:" + width + "x" + height); LogUtils.d(TAG, String.format("裁剪启动 是否自由裁剪:%b目标尺寸%dx%d", isFreeCrop, width, height));
} }
} }

View File

@@ -14,7 +14,7 @@ import java.io.Serializable;
* @Date 2024/04/29 17:24:53 * @Date 2024/04/29 17:24:53
* @Describe 应用运行参数类 * @Describe 应用运行参数类
* 适配 API30支持 Serializable 持久化、Parcelable Intent 传递、JSON 序列化/反序列化 * 适配 API30支持 Serializable 持久化、Parcelable Intent 传递、JSON 序列化/反序列化
* 包含耗电提醒、充电提醒、电量检测、铃声提醒等核心配置 * 包含耗电提醒、充电提醒、电量检测、铃声提醒、相框尺寸等核心配置
*/ */
public class AppConfigBean extends BaseBean implements Serializable, Parcelable { public class AppConfigBean extends BaseBean implements Serializable, Parcelable {
// ====================== 静态常量(首屏可见,统一管理) ====================== // ====================== 静态常量(首屏可见,统一管理) ======================
@@ -28,8 +28,12 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
private static final int BATTERY_MIN = 0; // 电量最小值 private static final int BATTERY_MIN = 0; // 电量最小值
private static final int BATTERY_MAX = 100; // 电量最大值 private static final int BATTERY_MAX = 100; // 电量最大值
private static final int INVALID_BATTERY = -1; // 无效电量标识 private static final int INVALID_BATTERY = -1; // 无效电量标识
private static final int MIN_FRAME_SIZE = 100; // 最小相框尺寸px
private static final int MAX_FRAME_SIZE = 2000; // 最大相框尺寸px
private static final int DEFAULT_FRAME_WIDTH = 500; // 默认相框宽度px
private static final int DEFAULT_FRAME_HEIGHT = 500; // 默认相框高度px
// ====================== 成员变量(按功能分类:提醒配置→电量状态→检测配置) ====================== // ====================== 成员变量(按功能分类:提醒配置→电量状态→检测配置→相框配置 ======================
// 耗电提醒配置 // 耗电提醒配置
boolean isEnableUsageReminder = false; // 耗电提醒开关 boolean isEnableUsageReminder = false; // 耗电提醒开关
int usageReminderValue = 45; // 耗电提醒阈值0-100 int usageReminderValue = 45; // 耗电提醒阈值0-100
@@ -43,6 +47,9 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
int currentBatteryValue = INVALID_BATTERY; // 当前电池电量(统一命名,替代原 currentValue int currentBatteryValue = INVALID_BATTERY; // 当前电池电量(统一命名,替代原 currentValue
// 电量检测配置 // 电量检测配置
int batteryDetectInterval = 2000; // 电量检测间隔ms适配 RemindThread int batteryDetectInterval = 2000; // 电量检测间隔ms适配 RemindThread
// 相框配置
int defaultFrameWidth = DEFAULT_FRAME_WIDTH; // 默认相框宽度px
int defaultFrameHeight = DEFAULT_FRAME_HEIGHT; // 默认相框高度px
// ====================== 构造方法(初始化默认配置,强化默认值校验) ====================== // ====================== 构造方法(初始化默认配置,强化默认值校验) ======================
public AppConfigBean() { public AppConfigBean() {
@@ -53,6 +60,8 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
setReminderIntervalTime(5000); setReminderIntervalTime(5000);
setBatteryDetectInterval(1000); // 默认检测间隔1秒 setBatteryDetectInterval(1000); // 默认检测间隔1秒
setCurrentBatteryValue(INVALID_BATTERY); // 初始化无效电量标识 setCurrentBatteryValue(INVALID_BATTERY); // 初始化无效电量标识
setDefaultFrameWidth(DEFAULT_FRAME_WIDTH); // 初始化默认相框宽度
setDefaultFrameHeight(DEFAULT_FRAME_HEIGHT); // 初始化默认相框高度
LogUtils.d(TAG, "AppConfigBean: 初始化默认配置完成"); LogUtils.d(TAG, "AppConfigBean: 初始化默认配置完成");
} }
@@ -169,6 +178,35 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
return batteryDetectInterval; return batteryDetectInterval;
} }
// --------------- 相框配置相关 ---------------
/**
* 设置默认相框宽度
* @param defaultFrameWidth 相框宽度px范围 MIN_FRAME_SIZE - MAX_FRAME_SIZE
*/
public void setDefaultFrameWidth(int defaultFrameWidth) {
this.defaultFrameWidth = Math.min(Math.max(defaultFrameWidth, MIN_FRAME_SIZE), MAX_FRAME_SIZE);
LogUtils.d(TAG, String.format("setDefaultFrameWidth: 默认相框宽度设置为 %dpx输入值%d",
this.defaultFrameWidth, defaultFrameWidth));
}
public int getDefaultFrameWidth() {
return defaultFrameWidth;
}
/**
* 设置默认相框高度
* @param defaultFrameHeight 相框高度px范围 MIN_FRAME_SIZE - MAX_FRAME_SIZE
*/
public void setDefaultFrameHeight(int defaultFrameHeight) {
this.defaultFrameHeight = Math.min(Math.max(defaultFrameHeight, MIN_FRAME_SIZE), MAX_FRAME_SIZE);
LogUtils.d(TAG, String.format("setDefaultFrameHeight: 默认相框高度设置为 %dpx输入值%d",
this.defaultFrameHeight, defaultFrameHeight));
}
public int getDefaultFrameHeight() {
return defaultFrameHeight;
}
// ====================== JSON 序列化/反序列化(兼容旧配置,补充调试日志) ====================== // ====================== JSON 序列化/反序列化(兼容旧配置,补充调试日志) ======================
@Override @Override
public String getName() { public String getName() {
@@ -189,8 +227,11 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
// 兼容旧字段 currentValue同步新字段 currentBatteryValue // 兼容旧字段 currentValue同步新字段 currentBatteryValue
jsonWriter.name("currentBatteryValue").value(bean.getCurrentBatteryValue()); jsonWriter.name("currentBatteryValue").value(bean.getCurrentBatteryValue());
jsonWriter.name("currentValue").value(bean.getCurrentBatteryValue()); jsonWriter.name("currentValue").value(bean.getCurrentBatteryValue());
// 新增字段序列化 // 新增字段序列化(检测配置)
jsonWriter.name("batteryDetectInterval").value(bean.getBatteryDetectInterval()); jsonWriter.name("batteryDetectInterval").value(bean.getBatteryDetectInterval());
// 新增字段序列化(相框配置)
jsonWriter.name("defaultFrameWidth").value(bean.getDefaultFrameWidth());
jsonWriter.name("defaultFrameHeight").value(bean.getDefaultFrameHeight());
LogUtils.d(TAG, "writeThisToJsonWriter: JSON 序列化完成"); LogUtils.d(TAG, "writeThisToJsonWriter: JSON 序列化完成");
} }
@@ -223,6 +264,12 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
LogUtils.d(TAG, "readBeanFromJsonReader: 读取新字段 currentBatteryValue 完成"); LogUtils.d(TAG, "readBeanFromJsonReader: 读取新字段 currentBatteryValue 完成");
} else if (name.equals("batteryDetectInterval")) { } else if (name.equals("batteryDetectInterval")) {
bean.setBatteryDetectInterval(jsonReader.nextInt()); bean.setBatteryDetectInterval(jsonReader.nextInt());
} else if (name.equals("defaultFrameWidth")) {
bean.setDefaultFrameWidth(jsonReader.nextInt());
LogUtils.d(TAG, "readBeanFromJsonReader: 读取字段 defaultFrameWidth 完成");
} else if (name.equals("defaultFrameHeight")) {
bean.setDefaultFrameHeight(jsonReader.nextInt());
LogUtils.d(TAG, "readBeanFromJsonReader: 读取字段 defaultFrameHeight 完成");
} else { } else {
jsonReader.skipValue(); jsonReader.skipValue();
LogUtils.w(TAG, String.format("readBeanFromJsonReader: 跳过未知字段 %s", name)); LogUtils.w(TAG, String.format("readBeanFromJsonReader: 跳过未知字段 %s", name));
@@ -250,6 +297,9 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
dest.writeByte((byte) (isCharging ? 1 : 0)); dest.writeByte((byte) (isCharging ? 1 : 0));
dest.writeInt(currentBatteryValue); dest.writeInt(currentBatteryValue);
dest.writeInt(batteryDetectInterval); dest.writeInt(batteryDetectInterval);
// 新增相框配置字段写入
dest.writeInt(defaultFrameWidth);
dest.writeInt(defaultFrameHeight);
LogUtils.d(TAG, "writeToParcel: Parcel 序列化完成"); LogUtils.d(TAG, "writeToParcel: Parcel 序列化完成");
} }
@@ -267,6 +317,9 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
bean.isCharging = source.readByte() != 0; bean.isCharging = source.readByte() != 0;
bean.currentBatteryValue = source.readInt(); bean.currentBatteryValue = source.readInt();
bean.batteryDetectInterval = source.readInt(); bean.batteryDetectInterval = source.readInt();
// 新增相框配置字段读取
bean.defaultFrameWidth = source.readInt();
bean.defaultFrameHeight = source.readInt();
LogUtils.d(TAG, "createFromParcel: Parcel 反序列化完成"); LogUtils.d(TAG, "createFromParcel: Parcel 反序列化完成");
return bean; return bean;
} }

View File

@@ -96,7 +96,7 @@ public class AppConfigUtils {
/** /**
* 保存应用配置(内部核心方法,直接持久化) * 保存应用配置(内部核心方法,直接持久化)
*/ */
private void saveAppConfig() { public void saveAppConfig() {
AppConfigBean.saveBean(mContext, mAppConfigBean); AppConfigBean.saveBean(mContext, mAppConfigBean);
LogUtils.d(TAG, "saveAppConfig应用配置保存成功"); LogUtils.d(TAG, "saveAppConfig应用配置保存成功");
} }

View File

@@ -6,9 +6,8 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import java.io.File; import java.io.File;
@@ -19,20 +18,24 @@ import java.io.OutputStream;
/** /**
* 图片处理工具类(质量压缩专用) * 图片处理工具类(质量压缩专用)
* 功能:对图片进行JPEG质量压缩并将压缩结果覆盖源文件获取主题colorPrimary颜色值 * 功能:1. 图片JPEG质量压缩覆盖源文件2. 获取主题colorAccent颜色3. 位图纯色背景合成
* 适配Java 7 + Android API 30 * 适配Java 7 + Android API 30
* 核心逻辑:Bitmap.compress 质量压缩 + FileChannel 高效文件复制;主题属性解析 * 核心逻辑:
* - 压缩Bitmap.compress + FileChannel 高效文件复制
* - 主题颜色TypedArray 解析主题属性
* - 位图合成Canvas 绘制(支持透明通道)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com> * @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/ */
public class ImageUtils { public class ImageUtils {
// ================================== 静态常量区(置顶归类,消除魔法值)================================= // ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = "ImageUtils"; public static final String TAG = "ImageUtils";
private static final Bitmap.CompressFormat COMPRESS_FORMAT = Bitmap.CompressFormat.JPEG; private static final Bitmap.CompressFormat COMPRESS_FORMAT = Bitmap.CompressFormat.JPEG;
private static final int MIN_COMPRESS_QUALITY = 0; private static final int MIN_COMPRESS_QUALITY = 0;
private static final int MAX_COMPRESS_QUALITY = 100; private static final int MAX_COMPRESS_QUALITY = 100;
private static final int[] COLOR_ACCENT_ATTR = new int[]{R.attr.colorAccent}; // colorPrimary属性数组 private static final int[] COLOR_ACCENT_ATTR = new int[]{R.attr.colorAccent}; // colorAccent属性数组
// ================================== 新增Accent 颜色获取方法 ================================= // ================================== 主题颜色获取方法 =================================
/** /**
* 从当前应用主题中获取 colorAccent 颜色值 * 从当前应用主题中获取 colorAccent 颜色值
* @param context 上下文,用于获取主题与资源 * @param context 上下文,用于获取主题与资源
@@ -40,14 +43,15 @@ public class ImageUtils {
*/ */
public static int getColorAccent(Context context) { public static int getColorAccent(Context context) {
LogUtils.d(TAG, "【getColorAccent】方法调用"); LogUtils.d(TAG, "【getColorAccent】方法调用");
// 参数校验
if (context == null) { if (context == null) {
LogUtils.e(TAG, "【getColorAccent】参数异常Context为空,返回默认颜色"); LogUtils.e(TAG, "【getColorAccent】参数异常Context为空");
return Color.parseColor("#FFFFFFFF"); return Color.parseColor("#FFFFFFFF");
} }
TypedArray typedArray = null; TypedArray typedArray = null;
try { try {
// 从当前主题解析 colorAccent 属性 // 从主题解析属性
typedArray = context.obtainStyledAttributes(COLOR_ACCENT_ATTR); typedArray = context.obtainStyledAttributes(COLOR_ACCENT_ATTR);
int colorAccent = typedArray.getColor(0, Color.parseColor("#FFFFFFFF")); int colorAccent = typedArray.getColor(0, Color.parseColor("#FFFFFFFF"));
LogUtils.d(TAG, String.format("【getColorAccent】解析成功 | colorAccent=0x%08X", colorAccent)); LogUtils.d(TAG, String.format("【getColorAccent】解析成功 | colorAccent=0x%08X", colorAccent));
@@ -56,7 +60,7 @@ public class ImageUtils {
LogUtils.e(TAG, "【getColorAccent】解析失败返回默认颜色", e); LogUtils.e(TAG, "【getColorAccent】解析失败返回默认颜色", e);
return Color.parseColor("#FFFFFFFF"); return Color.parseColor("#FFFFFFFF");
} finally { } finally {
// 回收TypedArray资源避免内存泄漏 // 回收资源
if (typedArray != null) { if (typedArray != null) {
typedArray.recycle(); typedArray.recycle();
LogUtils.d(TAG, "【getColorAccent】TypedArray资源已回收"); LogUtils.d(TAG, "【getColorAccent】TypedArray资源已回收");
@@ -64,7 +68,13 @@ public class ImageUtils {
} }
} }
public static Bitmap drawBitmapOnSolidBackground(final int bgColor, int originalFrameW, int originalFrameH, Bitmap fgBitmap) { public static Bitmap drawBitmapOnSolidBackground(final int bgColor, int originalFrameW, int originalFrameH, Bitmap fgBitmap) {
// 方法调用及入参日志
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】方法调用 | 背景色=0x%08X | 目标尺寸=%dx%d | 前景位图=%s",
bgColor, originalFrameW, originalFrameH,
(fgBitmap != null ? fgBitmap.getWidth() + "x" + fgBitmap.getHeight() : "null")));
// 1. 严格参数校验 // 1. 严格参数校验
if (fgBitmap == null || fgBitmap.isRecycled()) { if (fgBitmap == null || fgBitmap.isRecycled()) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常前景Bitmap为空或已回收"); LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常前景Bitmap为空或已回收");
@@ -79,49 +89,55 @@ public class ImageUtils {
return null; return null;
} }
// 计算原画框宽高比核心返回位图尺寸严格为originalFrameW×originalFrameH比例自然一致 // 2. 强制画布尺寸为目标尺寸
float frameRatio = (float) originalFrameW / originalFrameH; int canvasW = originalFrameW;
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】原画框目标尺寸=%dx%d | 画框比例=%.2f", int canvasH = originalFrameH;
originalFrameW, originalFrameH, frameRatio)); LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】画布尺寸已确定%dx%d", canvasW, canvasH));
// 3. 核心逻辑强制画布尺寸为originalFrameW×originalFrameH满足需求 // 3. 创建结果位图ARGB_8888支持透明通道
int extendedCanvasW = originalFrameW; Bitmap resultBitmap = Bitmap.createBitmap(canvasW, canvasH, Bitmap.Config.ARGB_8888);
int extendedCanvasH = originalFrameH;
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】画布尺寸强制目标尺寸=%dx%d | 实际比例=%.2f(与画框一致)",
extendedCanvasW, extendedCanvasH, (float) extendedCanvasW / extendedCanvasH));
// 4. 创建与目标尺寸完全一致的结果BitmapARGB_8888 格式支持透明通道)
Bitmap resultBitmap = Bitmap.createBitmap(extendedCanvasW, extendedCanvasH, Bitmap.Config.ARGB_8888);
if (resultBitmap == null) { if (resultBitmap == null) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】创建结果Bitmap失败"); LogUtils.e(TAG, "【drawBitmapOnSolidBackground】创建结果Bitmap失败");
return null; return null;
} }
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】结果Bitmap尺寸=%dx%d | 比例=%.2f",
resultBitmap.getWidth(), resultBitmap.getHeight(), (float) resultBitmap.getWidth() / resultBitmap.getHeight()));
// 5. 画布绘制:先画满纯色背景,再画带透明的居中前景 // 4. 画布绘制
Canvas canvas = new Canvas(resultBitmap); Canvas canvas = new Canvas(resultBitmap);
try { try {
// 5.1 绘制纯色背景(填满整个目标尺寸画布) // 4.1 绘制纯色背景
canvas.drawRect(0, 0, extendedCanvasW, extendedCanvasH, new Paint() {{ Paint bgPaint = new Paint();
setColor(bgColor); bgPaint.setColor(bgColor);
setStyle(Paint.Style.FILL); bgPaint.setStyle(Paint.Style.FILL);
}}); canvas.drawRect(0, 0, canvasW, canvasH, bgPaint);
LogUtils.d(TAG, "【drawBitmapOnSolidBackground】纯色背景绘制完成填满目标尺寸");
// 5.2 计算前景在目标画布内的居中位置 // 4.2 计算前景 FIT_CENTER 变换参数(等比缩放至完全放入画布,居中显示)
float fgX = (extendedCanvasW - fgBitmap.getWidth()) / 2f; float fgWidth = fgBitmap.getWidth();
float fgY = (extendedCanvasH - fgBitmap.getHeight()) / 2f; float fgHeight = fgBitmap.getHeight();
float scaleX = (float) canvasW / fgWidth;
float scaleY = (float) canvasH / fgHeight;
float scale = Math.min(scaleX, scaleY); // 取最小比例,保证完全放入画布
// 5.3 绘制前景位图开启透明度支持保留Alpha通道 // 4.3 计算缩放后前景尺寸
// Paint fgPaint = new Paint(); float scaledW = fgWidth * scale;
// fgPaint.setAlpha(0); // 保持前景自身透明度默认255可根据需求调整 float scaledH = fgHeight * scale;
// fgPaint.setAntiAlias(true); // 可选:抗锯齿,让边缘更平滑
// fgPaint.setDither(true); // 可选:抖动,提升色彩显示效果 // 4.4 计算居中位置(缩放后居中,无裁剪)
// canvas.drawBitmap(fgBitmap, fgX, fgY, fgPaint); float translateX = (canvasW - scaledW) / 2f;
// LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】前景位图居中完成 | 位置=(%.1f,%.1f)", float translateY = (canvasH - scaledH) / 2f;
// fgX, fgY));
// // 4.5 构建变换矩阵(缩放+平移,实现 FIT_CENTER 效果)
Matrix matrix = new Matrix();
matrix.postScale(scale, scale); // 等比缩放
matrix.postTranslate(translateX, translateY); // 居中平移
// 4.6 绘制前景(保留透明通道,抗锯齿)
Paint fgPaint = new Paint();
fgPaint.setAntiAlias(true);
fgPaint.setDither(true);
canvas.drawBitmap(fgBitmap, matrix, fgPaint);
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】合成成功 | 缩放比例=%.2f | 居中位置=(%.1f,%.1f) | 效果=FIT_CENTER",
scale, translateX, translateY));
return resultBitmap; return resultBitmap;
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】合成失败", e); LogUtils.e(TAG, "【drawBitmapOnSolidBackground】合成失败", e);
@@ -133,17 +149,19 @@ public class ImageUtils {
} }
// ================================== 核心工具方法(图片质量压缩)================================= // ================================== 核心压缩方法 =================================
/** /**
* 图片质量压缩JPEG格式压缩后覆盖源文件 * 图片质量压缩JPEG格式压缩后覆盖源文件
* @param context 上下文(备用,当前逻辑未直接使用 * @param context 上下文(备用)
* @param srcImagePath 源图片文件路径(非空,文件需存在) * @param srcImagePath 源图片文件路径(非空,文件需存在)
* @param dstImagePath 压缩后临时保存路径(非空,用于存储压缩中间文件 * @param dstImagePath 压缩后临时保存路径(非空)
* @param compressQuality 压缩质量0-100数值越小压缩率越高 * @param compressQuality 压缩质量0-100数值越小压缩率越高
*/ */
public static void bitmapCompress(Context context, String srcImagePath, String dstImagePath, int compressQuality) { public static void bitmapCompress(Context context, String srcImagePath, String dstImagePath, int compressQuality) {
LogUtils.d(TAG, String.format("【bitmapCompress】调用开始 | 源路径=%s | 临时路径=%s | 压缩质量=%d", // 方法调用及入参日志
LogUtils.d(TAG, String.format("【bitmapCompress】方法调用 | 源路径=%s | 临时路径=%s | 压缩质量=%d",
srcImagePath, dstImagePath, compressQuality)); srcImagePath, dstImagePath, compressQuality));
// 1. 前置参数校验 // 1. 前置参数校验
if (srcImagePath == null || srcImagePath.isEmpty()) { if (srcImagePath == null || srcImagePath.isEmpty()) {
LogUtils.e(TAG, "【bitmapCompress】参数异常源文件路径为空"); LogUtils.e(TAG, "【bitmapCompress】参数异常源文件路径为空");
@@ -176,7 +194,7 @@ public class ImageUtils {
LogUtils.d(TAG, String.format("【bitmapCompress】Bitmap解码成功 | 尺寸=%dx%d", LogUtils.d(TAG, String.format("【bitmapCompress】Bitmap解码成功 | 尺寸=%dx%d",
compressBitmap.getWidth(), compressBitmap.getHeight())); compressBitmap.getWidth(), compressBitmap.getHeight()));
// 3. 创建临时压缩文件 // 3. 创建临时压缩文件目录
File dstFile = new File(dstImagePath); File dstFile = new File(dstImagePath);
File dstParentDir = dstFile.getParentFile(); File dstParentDir = dstFile.getParentFile();
if (dstParentDir != null && !dstParentDir.exists()) { if (dstParentDir != null && !dstParentDir.exists()) {
@@ -204,7 +222,7 @@ public class ImageUtils {
} catch (IOException e) { } catch (IOException e) {
LogUtils.e(TAG, "【bitmapCompress】IO异常", e); LogUtils.e(TAG, "【bitmapCompress】IO异常", e);
} finally { } finally {
// 6. 资源释放:关闭输出流 // 6. 关闭输出流
if (outputStream != null) { if (outputStream != null) {
try { try {
outputStream.close(); outputStream.close();
@@ -212,7 +230,7 @@ public class ImageUtils {
LogUtils.e(TAG, "【bitmapCompress】输出流关闭失败", e); LogUtils.e(TAG, "【bitmapCompress】输出流关闭失败", e);
} }
} }
// 7. 资源释放:回收Bitmap // 7. 回收Bitmap
if (compressBitmap != null && !compressBitmap.isRecycled()) { if (compressBitmap != null && !compressBitmap.isRecycled()) {
compressBitmap.recycle(); compressBitmap.recycle();
LogUtils.d(TAG, "【bitmapCompress】Bitmap资源已回收"); LogUtils.d(TAG, "【bitmapCompress】Bitmap资源已回收");

View File

@@ -9,68 +9,69 @@ import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import java.io.File;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.ImageUtils; import cc.winboll.studio.powerbell.utils.ImageUtils;
import java.io.File;
/** /**
* 基于Java7的BackgroundViewLinearLayout+ImageView保持原图比例居中平铺 * 基于Java7的BackgroundViewLinearLayout+ImageView保持原图比例居中平铺
* 核心ImageView保持原图比例在LinearLayout中居中平铺无拉伸、无裁剪、无压缩 * 核心ImageView保持原图比例在LinearLayout中居中平铺无拉伸、无裁剪、无压缩
* 改进:强制保持缓存策略,无论内存是否紧张,不自动清理任何缓存,保留图片原始品质 * 改进:强制保持缓存策略,无论内存是否紧张,不自动清理任何缓存,保留图片原始品质
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/ */
public class BackgroundView extends RelativeLayout { public class BackgroundView extends RelativeLayout {
// ====================================== 静态常量区 ====================================== // ====================================== 静态常量区(首屏可见,统一管理) ======================================
public static final String TAG = "BackgroundView"; public static final String TAG = "BackgroundView";
// Bitmap 配置常量(原始品质) // Bitmap 配置常量(原始品质)
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int BITMAP_SAMPLE_SIZE = 1; // 不缩放采样率 private static final int BITMAP_SAMPLE_SIZE = 1; // 不缩放采样率
// ====================================== 成员变量区 ====================================== // ====================================== 成员变量区(按功能分类:上下文→视图→缓存→图片属性) ======================================
// 缓存相关 // 上下文
private String mCurrentCachedPath = "";
// 视图相关
private Context mContext; private Context mContext;
private LinearLayout mLlContainer; // 主容器LinearLayout // 视图组件
private ImageView mIvBackground; // 图片显示控件 private LinearLayout mLlContainer; // 主容器LinearLayout
private ImageView mIvBackground; // 图片显示控件
// 缓存相关
private String mCurrentCachedPath = "";// 当前缓存图片路径
// 图片属性 // 图片属性
private float mImageAspectRatio = 1.0f; // 原图宽高比(宽/高) private float mImageAspectRatio = 1.0f;// 原图宽高比(宽/高)
// 当前图片背景 private int mBgColor = 0xFFFFFFFF; // 当前图片背景
private int mbgColor = 0xFFFFFFFF;
// 当前背景画框尺寸
ViewGroup.LayoutParams mbgLayoutParams;
// ====================================== 构造器Java7兼容 ====================================== // ====================================== 构造器Java7兼容,按参数重载顺序排列 ======================================
public BackgroundView(Context context) { public BackgroundView(Context context) {
super(context); super(context);
LogUtils.d(TAG, "=== BackgroundView 构造器1启动 [context] ==="); LogUtils.d(TAG, "BackgroundView() 构造器1启动 | context=" + context.getClass().getSimpleName());
this.mContext = context; this.mContext = context;
initView(); initView();
} }
public BackgroundView(Context context, AttributeSet attrs) { public BackgroundView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
LogUtils.d(TAG, "=== BackgroundView 构造器2启动 [context, attrs] ==="); LogUtils.d(TAG, "BackgroundView(Context, AttributeSet) 构造器2启动 | context=" + context.getClass().getSimpleName());
this.mContext = context; this.mContext = context;
initView(); initView();
} }
public BackgroundView(Context context, AttributeSet attrs, int defStyleAttr) { public BackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
LogUtils.d(TAG, "=== BackgroundView 构造器3启动 [context, attrs, defStyleAttr] ==="); LogUtils.d(TAG, "BackgroundView(Context, AttributeSet, int) 构造器3启动 | context=" + context.getClass().getSimpleName());
this.mContext = context; this.mContext = context;
initView(); initView();
} }
// ====================================== 初始化方法 ====================================== // ====================================== 初始化方法(按执行顺序:主视图→子容器→图片控件→默认背景) ======================================
private void initView() { private void initView() {
LogUtils.d(TAG, "=== initView 启动 ==="); LogUtils.d(TAG, "initView() 启动");
// 1. 配置当前控件:全屏+透明 // 1. 配置当前控件:全屏+透明
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// 2. 初始化主容器LinearLayout // 2. 初始化主容器LinearLayout
@@ -79,11 +80,11 @@ public class BackgroundView extends RelativeLayout {
initImageView(); initImageView();
// 4. 初始设置透明背景 // 4. 初始设置透明背景
setDefaultEmptyBackground(); setDefaultEmptyBackground();
LogUtils.d(TAG, "=== initView 完成 ==="); LogUtils.d(TAG, "initView() 完成");
} }
private void initLinearLayout() { private void initLinearLayout() {
LogUtils.d(TAG, "=== initLinearLayout 启动 ==="); LogUtils.d(TAG, "initLinearLayout() 启动");
mLlContainer = new LinearLayout(mContext); mLlContainer = new LinearLayout(mContext);
LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
@@ -92,202 +93,133 @@ public class BackgroundView extends RelativeLayout {
mLlContainer.setLayoutParams(llParams); mLlContainer.setLayoutParams(llParams);
mLlContainer.setOrientation(LinearLayout.VERTICAL); mLlContainer.setOrientation(LinearLayout.VERTICAL);
mLlContainer.setGravity(android.view.Gravity.CENTER); mLlContainer.setGravity(android.view.Gravity.CENTER);
//mLlContainer.setBackgroundColor(0x00000000);
this.addView(mLlContainer); this.addView(mLlContainer);
LogUtils.d(TAG, "=== initLinearLayout 完成 ==="); LogUtils.d(TAG, "initLinearLayout() 完成");
} }
private void initImageView() { private void initImageView() {
LogUtils.d(TAG, "=== initImageView 启动 ==="); LogUtils.d(TAG, "initImageView() 启动");
mIvBackground = new ImageView(mContext); mIvBackground = new ImageView(mContext);
LinearLayout.LayoutParams ivParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams ivParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT LinearLayout.LayoutParams.WRAP_CONTENT
); );
mIvBackground.setLayoutParams(ivParams); mIvBackground.setLayoutParams(ivParams);
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER); mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
//mIvBackground.setBackgroundColor(0x00000000);
mLlContainer.addView(mIvBackground); mLlContainer.addView(mIvBackground);
LogUtils.d(TAG, "=== initImageView 完成 ==="); LogUtils.d(TAG, "initImageView() 完成");
} }
// ====================================== 对外方法 ====================================== // ====================================== 对外公开方法按功能分类Bean加载→图片加载 ======================================
public void loadByBackgroundBean(BackgroundBean bean) { public void loadByBackgroundBean(BackgroundBean bean) {
loadByBackgroundBean(bean, false); loadByBackgroundBean(bean, false);
} }
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) { public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
LogUtils.d(TAG, "=== loadByBackgroundBean 启动 [isRefresh:" + isRefresh + "] ==="); LogUtils.d(TAG, String.format("loadByBackgroundBean() 启动 | isRefresh=%b | bean=%s", isRefresh, bean));
// 参数校验 // 参数校验
if (bean == null) { if (bean == null) {
LogUtils.e(TAG, "loadByBackgroundBean: BackgroundBean为空"); LogUtils.e(TAG, "loadByBackgroundBean() 异常:BackgroundBean为空");
setDefaultEmptyBackground(); setDefaultEmptyBackground();
return; return;
} }
// 设置图片背景 // 设置图片背景
mbgColor = bean.getPixelColor(); mBgColor = bean.getPixelColor();
// 判断是否使用背景文件 // 判断是否使用背景文件
if (!bean.isUseBackgroundFile()) { if (!bean.isUseBackgroundFile()) {
LogUtils.d(TAG, "loadByBackgroundBean: 不使用背景文件,设置透明背景"); LogUtils.d(TAG, "loadByBackgroundBean() 不使用背景文件,设置透明背景");
setDefaultEmptyBackground(); setDefaultEmptyBackground();
return; return;
} }
// 获取目标路径 // 获取目标路径
String targetPath = bean.isUseBackgroundScaledCompressFile() String targetPath = bean.isUseBackgroundScaledCompressFile()
? bean.getBackgroundScaledCompressFilePath() ? bean.getBackgroundScaledCompressFilePath()
: bean.getBackgroundFilePath(); : bean.getBackgroundFilePath();
LogUtils.d(TAG, "loadByBackgroundBean: 目标路径=" + targetPath); LogUtils.d(TAG, String.format("loadByBackgroundBean() 目标路径=%s", targetPath));
// 校验文件是否存在 // 校验文件是否存在
File targetFile = new File(targetPath); File targetFile = new File(targetPath);
if (!targetFile.exists() || !targetFile.isFile()) { if (!targetFile.exists() || !targetFile.isFile()) {
LogUtils.e(TAG, "loadByBackgroundBean: 视图控件图片不存在:" + targetPath); LogUtils.e(TAG, "loadByBackgroundBean() 异常:图片文件不存在 | path=" + targetPath);
return; return;
} }
loadImage(mbgColor, targetPath, isRefresh);
loadImage(mBgColor, targetPath, isRefresh);
} }
public void loadImage(int bgColor, String imagePath, boolean isRefresh) { public void loadImage(int bgColor, String imagePath, boolean isRefresh) {
// 3. 隐藏ImageView防止闪烁 LogUtils.d(TAG, String.format("loadImage() 启动 | bgColor=0x%08X | imagePath=%s | isRefresh=%b", bgColor, imagePath, isRefresh));
mIvBackground.setVisibility(View.GONE); // 隐藏ImageView防止闪烁
// 计算画框尺寸 mIvBackground.setVisibility(View.GONE);
//mbgLayoutParams = adjustImageViewSize();
mbgLayoutParams = mLlContainer.getLayoutParams(); // 初始化配置工具类并保存默认相框尺寸
AppConfigUtils appConfigUtils = AppConfigUtils.getInstance(mContext);
appConfigUtils.loadAppConfig();
if (getWidth() > 0 && getHeight() > 0) {
appConfigUtils.mAppConfigBean.setDefaultFrameWidth(getWidth());
appConfigUtils.mAppConfigBean.setDefaultFrameHeight(getHeight());
appConfigUtils.saveAppConfig();
LogUtils.d(TAG, String.format("loadImage() 保存默认相框尺寸 | width=%d | height=%d", getWidth(), getHeight()));
}
// 刷新逻辑:重新解码原始品质图片并更新缓存 // 刷新逻辑:重新解码原始品质图片并更新缓存
if (isRefresh) { if (isRefresh) {
LogUtils.d(TAG, "loadByBackgroundBean: 刷新图片,重新解码原始品质图片并更新缓存"); LogUtils.d(TAG, "loadImage() 执行刷新逻辑:重新解码原始品质图片");
Bitmap newBitmap = decodeOriginalBitmap(new File(imagePath)); Bitmap newBitmap = decodeOriginalBitmap(new File(imagePath));
// 合成纯色背景图片
// Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(bgColor,
// appConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
// appConfigUtils.mAppConfigBean.getDefaultFrameHeight(),
// newBitmap);
Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(bgColor,
1197,
2287,
newBitmap);
// ======================== 核心集成调用drawBitmapOnSolidBackground合成 ======================== if (combinedBitmap == null) {
//Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(mbgColor, mbgLayoutParams.width, mbgLayoutParams.height, newBitmap); ToastUtils.show("合成背景图片失败,使用原始图片");
Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(0xFF112233, mbgLayoutParams.width, mbgLayoutParams.height, newBitmap); LogUtils.e(TAG, "loadImage() 纯色背景合成失败,使用原始Bitmap");
if (combinedBitmap == null) { combinedBitmap = newBitmap;
LogUtils.e(TAG, "loadImage: 纯色背景合成失败使用原始Bitmap"); } else {
combinedBitmap = newBitmap; ToastUtils.show("合成背景图片成功");
} else { LogUtils.d(TAG, "loadImage() 纯色背景合成成功");
LogUtils.d(TAG, "loadImage: 纯色背景合成成功,尺寸与原始图一致"); // 回收原始Bitmap避免重复缓存
// 合成成功后回收原始Bitmap避免重复缓存 if (newBitmap != null && !newBitmap.isRecycled() && newBitmap != combinedBitmap) {
if (newBitmap != null && !newBitmap.isRecycled() && newBitmap != combinedBitmap) { newBitmap.recycle();
newBitmap.recycle(); LogUtils.d(TAG, "loadImage() 原始Bitmap已回收");
LogUtils.d(TAG, "loadImage: 原始Bitmap已回收"); }
} }
}
// ======================== 合成逻辑结束 ======================== // 更新缓存
if (combinedBitmap != null) { if (combinedBitmap != null) {
App.sBitmapCacheUtils.clearAllCache();
App.sBitmapCacheUtils.cacheBitmap(imagePath, combinedBitmap); App.sBitmapCacheUtils.cacheBitmap(imagePath, combinedBitmap);
App.sBitmapCacheUtils.increaseRefCount(imagePath); App.sBitmapCacheUtils.increaseRefCount(imagePath);
mCurrentCachedPath = imagePath; mCurrentCachedPath = imagePath;
LogUtils.d(TAG, "loadByBackgroundBean: 刷新缓存成功,路径=" + imagePath); LogUtils.d(TAG, String.format("loadImage() 刷新缓存成功 | path=%s", imagePath));
} else { } else {
LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + imagePath); LogUtils.e(TAG, String.format("loadImage() 刷新解码失败 | path=%s", imagePath));
} }
} }
// 加载图片 // 加载缓存图片
Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath); Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
// LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mIvBackground.getLayoutParams();
// params.width = mbgLayoutParams.width;
// params.height = mbgLayoutParams.height;
// mIvBackground.setLayoutParams(params);
// LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.MATCH_PARENT,
// LinearLayout.LayoutParams.MATCH_PARENT
// );
//mIvBackground.setLayoutParams(params);
mIvBackground.setImageBitmap(cachedBitmap); mIvBackground.setImageBitmap(cachedBitmap);
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER); mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setVisibility(View.VISIBLE); mIvBackground.setVisibility(View.VISIBLE);
LogUtils.d(TAG, "=== loadByBackgroundBean 完成 ==="); LogUtils.d(TAG, "loadImage() 完成");
} }
/** // ====================================== 内部工具方法按功能分类Bitmap校验→比例计算→解码→背景设置 ======================================
* 改进版:强制保持缓存策略,不自动清理任何缓存,强化引用计数管理,保留图片原始品质
* @param imagePath 图片绝对路径
*/
// public void loadImage2(String imagePath) {
// LogUtils.d(TAG, "=== loadImage 启动,路径:" + imagePath + "背景色0x%08X ===", mbgColor);
// // 1. 路径空校验
// if (TextUtils.isEmpty(imagePath)) {
// LogUtils.e(TAG, "loadImage: 图片路径为空");
// setDefaultEmptyBackground();
// return;
// }
// // 2. 文件有效性校验
// File imageFile = new File(imagePath);
// if (!imageFile.exists() || !imageFile.isFile()) {
// LogUtils.e(TAG, "loadImage: 图片文件无效");
// setDefaultEmptyBackground();
// return;
// }
//
// // ======================== 路径判断逻辑(强制缓存版) ========================
// // 3.1 路径未变化校验缓存有效性缓存的是合成后的Bitmap
// if (imagePath.equals(mCurrentCachedPath)) {
// Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
// if (isBitmapValid(cachedBitmap)) {
// LogUtils.d(TAG, "loadImage: 路径未变使用有效缓存Bitmap合成后品质");
// mImageAspectRatio = (float) cachedBitmap.getWidth() / cachedBitmap.getHeight();
// mIvBackground.setImageBitmap(cachedBitmap);
// mIvBackground.setVisibility(View.VISIBLE);
// LogUtils.d(TAG, "=== loadImage 完成(缓存命中) ===");
// return;
// } else {
// LogUtils.e(TAG, "loadImage: 缓存Bitmap无效尝试重加载并合成");
// }
// }
// // 3.2 路径已更新:保留旧缓存,仅更新路径记录
// if (!TextUtils.isEmpty(mCurrentCachedPath) && !mCurrentCachedPath.equals(imagePath)) {
// LogUtils.d(TAG, "loadImage: 路径已更新,保留旧缓存,原路径=" + mCurrentCachedPath + ",新路径=" + imagePath);
// }
// // ======================== 路径判断逻辑结束 ========================
//
// // 4. 计算图片宽高比(原始图片)
// if (!calculateImageAspectRatio(imageFile)) {
// setDefaultEmptyBackground();
// return;
// }
//
//
// // 5. 获取或解码Bitmap原始图
// Bitmap originalBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
// if (isBitmapValid(originalBitmap)) {
// LogUtils.d(TAG, "loadImage: 从缓存获取原始Bitmap准备合成");
// } else {
// LogUtils.d(TAG, "loadImage: 缓存未命中,解码原始品质图片");
// originalBitmap = decodeOriginalBitmap(imageFile);
// if (originalBitmap == null) {
// LogUtils.e(TAG, "loadImage: 图片解码失败(原始品质)");
// ToastUtils.show("图片解码失败,无法加载");
// setDefaultEmptyBackground();
// return;
// }
// }
//
// // 6. 缓存合成后的Bitmap替换原始图缓存
//// App.sBitmapCacheUtils.cacheBitmap(imagePath, originalBitmap);
//// LogUtils.d(TAG, "loadImage: 合成后图片缓存成功,路径=" + imagePath);
//// // 7. 引用计数管理
//// App.sBitmapCacheUtils.increaseRefCount(imagePath);
// // 8. 更新当前缓存路径
// mCurrentCachedPath = imagePath;
// // 9. 设置图片并调整尺寸
// //mIvBackground.setImageBitmap(originalBitmap);
//
// LogUtils.d(TAG, "=== loadImage 完成(合成后加载) ===");
// }
// ====================================== 内部工具方法 ======================================
/** /**
* 工具方法判断Bitmap是否有效非空且未被回收 * 工具方法判断Bitmap是否有效非空且未被回收
*/ */
private boolean isBitmapValid(Bitmap bitmap) { private boolean isBitmapValid(Bitmap bitmap) {
boolean valid = bitmap != null && !bitmap.isRecycled(); boolean valid = bitmap != null && !bitmap.isRecycled();
if (!valid) { if (!valid) {
LogUtils.w(TAG, "isBitmapValid: Bitmap无效(空或已回收"); LogUtils.w(TAG, "isBitmapValid() 无效:Bitmap空或已回收");
} }
return valid; return valid;
} }
@@ -296,25 +228,26 @@ public class BackgroundView extends RelativeLayout {
* 计算图片宽高比 * 计算图片宽高比
*/ */
private boolean calculateImageAspectRatio(File file) { private boolean calculateImageAspectRatio(File file) {
LogUtils.d(TAG, "=== calculateImageAspectRatio 启动,文件=" + file.getAbsolutePath() + " ==="); LogUtils.d(TAG, String.format("calculateImageAspectRatio() 启动 | file=%s", file.getAbsolutePath()));
try { try {
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options); BitmapFactory.decodeFile(file.getAbsolutePath(), options);
// 尺寸校验 // 尺寸校验
int width = options.outWidth; int width = options.outWidth;
int height = options.outHeight; int height = options.outHeight;
if (width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {
LogUtils.e(TAG, "calculateImageAspectRatio: 图片尺寸无效,宽=" + width + ",高=" + height); LogUtils.e(TAG, String.format("calculateImageAspectRatio() 无效尺寸 | width=%d | height=%d", width, height));
return false; return false;
} }
// 计算比例 // 计算比例
mImageAspectRatio = (float) width / height; mImageAspectRatio = (float) width / height;
LogUtils.d(TAG, "calculateImageAspectRatio: 原图比例=" + mImageAspectRatio); LogUtils.d(TAG, String.format("calculateImageAspectRatio() 完成 | 比例=%.2f", mImageAspectRatio));
LogUtils.d(TAG, "=== calculateImageAspectRatio 完成 ===");
return true; return true;
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "calculateImageAspectRatio: 计算比例失败:" + e.getMessage()); LogUtils.e(TAG, "calculateImageAspectRatio() 失败:" + e.getMessage());
return false; return false;
} }
} }
@@ -323,7 +256,7 @@ public class BackgroundView extends RelativeLayout {
* 移除压缩逻辑:解码原始品质图片(无缩放、无色彩损失) * 移除压缩逻辑:解码原始品质图片(无缩放、无色彩损失)
*/ */
private Bitmap decodeOriginalBitmap(File file) { private Bitmap decodeOriginalBitmap(File file) {
LogUtils.d(TAG, "=== decodeOriginalBitmap 启动,文件=" + file.getAbsolutePath() + " ==="); LogUtils.d(TAG, String.format("decodeOriginalBitmap() 启动 | file=%s", file.getAbsolutePath()));
try { try {
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
// 核心配置:原始品质 // 核心配置:原始品质
@@ -333,84 +266,40 @@ public class BackgroundView extends RelativeLayout {
options.inInputShareable = false; options.inInputShareable = false;
options.inDither = true; options.inDither = true;
options.inScaled = false; options.inScaled = false;
// 解码图片 // 解码图片
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options); Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
if (bitmap != null) { if (bitmap != null) {
LogUtils.d(TAG, "decodeOriginalBitmap: 解码成功,宽=" + bitmap.getWidth() + ",高=" + bitmap.getHeight()); LogUtils.d(TAG, String.format("decodeOriginalBitmap() 成功 | width=%d | height=%d", bitmap.getWidth(), bitmap.getHeight()));
} else { } else {
LogUtils.e(TAG, "decodeOriginalBitmap: 解码返回null"); LogUtils.e(TAG, "decodeOriginalBitmap() 失败:返回null");
} }
LogUtils.d(TAG, "=== decodeOriginalBitmap 完成 ===");
return bitmap; return bitmap;
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "decodeOriginalBitmap: 原始品质解码失败" + e.getMessage()); LogUtils.e(TAG, "decodeOriginalBitmap() 异常" + e.getMessage());
return null; return null;
} }
} }
/**
* 调整ImageView尺寸保持原图比例
*/
// private LinearLayout.LayoutParams adjustImageViewSize() {
// LogUtils.d(TAG, "=== adjustImageViewSize 启动 ===");
// // 空指针校验
// if (mLlContainer == null || mIvBackground == null) {
// LogUtils.e(TAG, "adjustImageViewSize: 容器或ImageView未初始化");
// return null;
// }
// // 获取容器尺寸
// int llWidth = mLlContainer.getWidth();
// int llHeight = mLlContainer.getHeight();
// if (llWidth == 0 || llHeight == 0) {
// LogUtils.w(TAG, "adjustImageViewSize: 容器尺寸未初始化,延迟调整");
// post(new Runnable() {
// @Override
// public void run() {
// adjustImageViewSize();
// }
// });
// return null;
// }
// // 计算ImageView尺寸
// int ivWidth, ivHeight;
// if (mImageAspectRatio >= 1.0f) {
// ivWidth = Math.min((int) (llHeight * mImageAspectRatio), llWidth);
// ivHeight = (int) (ivWidth / mImageAspectRatio);
// } else {
// ivHeight = Math.min((int) (llWidth / mImageAspectRatio), llHeight);
// ivWidth = (int) (ivHeight * mImageAspectRatio);
// }
// // 设置尺寸
// LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mIvBackground.getLayoutParams();
// params.width = ivWidth;
// params.height = ivHeight;
// mIvBackground.setLayoutParams(params);
// mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
// mIvBackground.setVisibility(View.VISIBLE);
// LogUtils.d(TAG, "adjustImageViewSize: 尺寸调整完成,宽=" + ivWidth + ",高=" + ivHeight);
// LogUtils.d(TAG, "=== adjustImageViewSize 完成 ===");
// return params;
// }
/** /**
* 设置默认透明背景,仅减少引用计数,不删除缓存 * 设置默认透明背景,仅减少引用计数,不删除缓存
*/ */
private void setDefaultEmptyBackground() { private void setDefaultEmptyBackground() {
LogUtils.d(TAG, "=== setDefaultTransparentBackground 启动 ==="); LogUtils.d(TAG, "setDefaultEmptyBackground() 启动");
// 清空ImageView // 清空ImageView
mIvBackground.setImageDrawable(null); mIvBackground.setImageDrawable(null);
//mIvBackground.setBackgroundColor(mbgColor);
mImageAspectRatio = 1.0f; mImageAspectRatio = 1.0f;
// 减少引用计数,不删除缓存 // 减少引用计数,不删除缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) { if (!TextUtils.isEmpty(mCurrentCachedPath)) {
LogUtils.d(TAG, "setDefaultTransparentBackground: 减少引用计数,路径=" + mCurrentCachedPath); LogUtils.d(TAG, String.format("setDefaultEmptyBackground() 减少引用计数 | path=%s", mCurrentCachedPath));
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath); App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
mCurrentCachedPath = ""; mCurrentCachedPath = "";
} }
LogUtils.d(TAG, "=== setDefaultTransparentBackground 完成 ==="); LogUtils.d(TAG, "setDefaultEmptyBackground() 完成");
} }
// ====================================== 重写生命周期方法 ====================================== // ====================================== 重写生命周期方法(按执行顺序:绘制→尺寸变化→窗口分离) ======================================
/** /**
* 重写绘制前强制校验Bitmap有效性防止已回收Bitmap崩溃 * 重写绘制前强制校验Bitmap有效性防止已回收Bitmap崩溃
*/ */
@@ -421,7 +310,7 @@ public class BackgroundView extends RelativeLayout {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap(); Bitmap bitmap = bitmapDrawable.getBitmap();
if (!isBitmapValid(bitmap)) { if (!isBitmapValid(bitmap)) {
LogUtils.e(TAG, "onDraw: 检测到已回收Bitmap清空本地绘制(保留全局缓存)"); LogUtils.e(TAG, "onDraw() 检测到已回收Bitmap清空绘制");
mIvBackground.setImageDrawable(null); mIvBackground.setImageDrawable(null);
return; return;
} }
@@ -429,34 +318,32 @@ public class BackgroundView extends RelativeLayout {
super.onDraw(canvas); super.onDraw(canvas);
} }
/**
* 重写View从窗口移除时仅减少引用计数不删除全局缓存强制保持策略
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
LogUtils.d(TAG, "=== onDetachedFromWindow 启动 ===");
// 清空ImageView的Drawable释放本地引用
mIvBackground.setImageDrawable(null);
// 减少引用计数,不删除全局缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
LogUtils.d(TAG, "onDetachedFromWindow: 减少引用计数,路径=" + mCurrentCachedPath);
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
mCurrentCachedPath = "";
}
LogUtils.d(TAG, "=== onDetachedFromWindow 完成 ===");
}
/** /**
* 重写恢复尺寸调整逻辑确保View尺寸变化时正确显示无压缩 * 重写恢复尺寸调整逻辑确保View尺寸变化时正确显示无压缩
*/ */
@Override @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh); super.onSizeChanged(w, h, oldw, oldh);
LogUtils.d(TAG, "onSizeChanged: 尺寸变化,宽=" + w + ",高=" + h + "调整ImageView尺寸"); LogUtils.d(TAG, String.format("onSizeChanged() 尺寸变化 | newW=%d | newH=%d | oldW=%d | oldH=%d", w, h, oldw, oldh));
//adjustImageViewSize(); }
// mbgLayoutParams.width = mLlContainer.getWidth();
// mbgLayoutParams.height = mLlContainer.getHeight(); /**
* 重写View从窗口移除时仅减少引用计数不删除全局缓存强制保持策略
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
LogUtils.d(TAG, "onDetachedFromWindow() 启动");
// 清空ImageView的Drawable释放本地引用
mIvBackground.setImageDrawable(null);
// 减少引用计数,不删除全局缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
LogUtils.d(TAG, String.format("onDetachedFromWindow() 减少引用计数 | path=%s", mCurrentCachedPath));
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
mCurrentCachedPath = "";
}
LogUtils.d(TAG, "onDetachedFromWindow() 完成");
} }
} }

View File

@@ -7,14 +7,15 @@ import android.util.AttributeSet;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
/** /**
* 单实例缓存版背景视图控件基于Java7- 强制缓存版 * 单实例缓存版背景视图控件基于Java7- 强制缓存版
* 核心:通过静态属性保存当前缓存路径和实例,支持强制重载图片 * 核心:通过静态属性保存当前缓存路径和实例,支持强制重载图片
* 新增SP持久化最后加载路径、获取最后加载实例功能 * 新增SP持久化最后加载路径、获取最后加载实例功能
* 强制缓存策略:无论内存是否紧张,不自动清理任何缓存实例和路径记录 * 强制缓存策略:无论内存是否紧张,不自动清理任何缓存实例和路径记录
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2025/12/21 20:43
*/ */
public class MemoryCachedBackgroundView extends BackgroundView { public class MemoryCachedBackgroundView extends BackgroundView {
// ====================================== 静态常量区TAG + SP相关常量 ====================================== // ====================================== 静态常量区TAG + SP相关常量 ======================================
@@ -34,19 +35,19 @@ public class MemoryCachedBackgroundView extends BackgroundView {
private MemoryCachedBackgroundView(Context context) { private MemoryCachedBackgroundView(Context context) {
super(context); super(context);
sInstanceCount++; sInstanceCount++;
LogUtils.d(TAG, "构造器1】创建MemoryCachedBackgroundView实例,当前实例总数" + sInstanceCount); LogUtils.d(TAG, String.format("构造器1启动 | 创建实例,当前实例总数=%d", sInstanceCount));
} }
private MemoryCachedBackgroundView(Context context, AttributeSet attrs) { private MemoryCachedBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
sInstanceCount++; sInstanceCount++;
LogUtils.d(TAG, "构造器2】创建MemoryCachedBackgroundView实例,当前实例总数" + sInstanceCount); LogUtils.d(TAG, String.format("构造器2启动 | 创建实例,当前实例总数=%d", sInstanceCount));
} }
private MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) { private MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
sInstanceCount++; sInstanceCount++;
LogUtils.d(TAG, "构造器3】创建MemoryCachedBackgroundView实例,当前实例总数" + sInstanceCount); LogUtils.d(TAG, String.format("构造器3启动 | 创建实例,当前实例总数=%d", sInstanceCount));
} }
// ====================================== 核心静态方法:获取/创建缓存实例(强制缓存版) ====================================== // ====================================== 核心静态方法:获取/创建缓存实例(强制缓存版) ======================================
@@ -58,32 +59,32 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @return 缓存/新创建的MemoryCachedBackgroundView实例 * @return 缓存/新创建的MemoryCachedBackgroundView实例
*/ */
public static MemoryCachedBackgroundView getInstance(Context context, int bgColor, String imagePath, boolean isReload) { public static MemoryCachedBackgroundView getInstance(Context context, int bgColor, String imagePath, boolean isReload) {
LogUtils.d(TAG, "getInstance调用 | 图片路径" + imagePath + " | 是否重载:" + isReload); LogUtils.d(TAG, String.format("getInstance 调用 | 图片路径=%s | 是否重载=%b", imagePath, isReload));
// 空路径校验 // 空路径校验
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "getInstance图片路径为空,创建空实例"); LogUtils.e(TAG, "getInstance: 图片路径为空,创建空实例");
return new MemoryCachedBackgroundView(context); return new MemoryCachedBackgroundView(context);
} }
// 1. 路径匹配缓存 → 判断是否强制重载 // 1. 路径匹配缓存 → 判断是否强制重载
if (imagePath.equals(sCachedImagePath) && sCachedView != null) { if (imagePath.equals(sCachedImagePath) && sCachedView != null) {
LogUtils.d(TAG, "getInstance路径已缓存,当前缓存实例有效"); LogUtils.d(TAG, "getInstance: 路径已缓存,当前缓存实例有效");
if (isReload) { if (isReload) {
LogUtils.d(TAG, "getInstance强制重载图片 | 路径" + imagePath); LogUtils.d(TAG, String.format("getInstance: 强制重载图片 | 路径=%s", imagePath));
sCachedView.loadImage(bgColor, imagePath, isReload); sCachedView.loadImage(bgColor, imagePath, isReload);
} else { } else {
LogUtils.d(TAG, "getInstance使用缓存实例,无需重载 | 路径" + imagePath); LogUtils.d(TAG, String.format("getInstance: 使用缓存实例,无需重载 | 路径=%s", imagePath));
} }
return sCachedView; return sCachedView;
} }
// 2. 路径不匹配/无缓存 → 新建实例并更新静态缓存(核心:保留旧实例,仅更新引用) // 2. 路径不匹配/无缓存 → 新建实例并更新静态缓存(核心:保留旧实例,仅更新引用)
LogUtils.d(TAG, "getInstance路径未缓存,新建实例(保留旧实例) | 路径" + imagePath); LogUtils.d(TAG, String.format("getInstance: 路径未缓存,新建实例(保留旧实例) | 路径=%s", imagePath));
String oldPath = sCachedImagePath; String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context); sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = imagePath; sCachedImagePath = imagePath;
sCachedView.loadImage(bgColor, imagePath, isReload); sCachedView.loadImage(bgColor, imagePath, isReload);
LogUtils.d(TAG, "getInstance已更新当前缓存实例,旧实例路径" + oldPath + "(强制保持)"); LogUtils.d(TAG, String.format("getInstance: 已更新当前缓存实例,旧实例路径=%s强制保持", oldPath));
return sCachedView; return sCachedView;
} }
@@ -95,28 +96,28 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @return 最后加载路径对应的实例 * @return 最后加载路径对应的实例
*/ */
public static MemoryCachedBackgroundView getLastInstance(Context context) { public static MemoryCachedBackgroundView getLastInstance(Context context) {
LogUtils.d(TAG, "getLastInstance调用"); LogUtils.d(TAG, "getLastInstance 调用");
// 1. 从SP获取最后加载的路径强制保持不自动删除 // 1. 从SP获取最后加载的路径强制保持不自动删除
String lastPath = getLastLoadImagePath(context); String lastPath = getLastLoadImagePath(context);
if (TextUtils.isEmpty(lastPath)) { if (TextUtils.isEmpty(lastPath)) {
LogUtils.e(TAG, "getLastInstance无最后加载路径,创建空实例"); LogUtils.e(TAG, "getLastInstance: 无最后加载路径,创建空实例");
return new MemoryCachedBackgroundView(context); return new MemoryCachedBackgroundView(context);
} }
// 2. 路径匹配当前缓存 → 直接返回 // 2. 路径匹配当前缓存 → 直接返回
if (lastPath.equals(sCachedImagePath) && sCachedView != null) { if (lastPath.equals(sCachedImagePath) && sCachedView != null) {
LogUtils.d(TAG, "getLastInstance使用最后路径缓存实例 | 路径" + lastPath); LogUtils.d(TAG, String.format("getLastInstance: 使用最后路径缓存实例 | 路径=%s", lastPath));
return sCachedView; return sCachedView;
} }
// 3. 路径不匹配 → 新建实例并更新缓存(保留旧实例) // 3. 路径不匹配 → 新建实例并更新缓存(保留旧实例)
LogUtils.d(TAG, "getLastInstance最后路径未缓存,新建实例并加载(保留旧实例) | 路径" + lastPath); LogUtils.d(TAG, String.format("getLastInstance: 最后路径未缓存,新建实例并加载(保留旧实例) | 路径=%s", lastPath));
String oldPath = sCachedImagePath; String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context); sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = lastPath; sCachedImagePath = lastPath;
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(context).getCurrentBackgroundBean().getPixelColor(); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(context).getCurrentBackgroundBean().getPixelColor();
sCachedView.loadImage(nCurrentPixelColor, sCachedImagePath, false); sCachedView.loadImage(nCurrentPixelColor, sCachedImagePath, false);
LogUtils.d(TAG, "getLastInstance已更新最后路径实例,旧实例路径" + oldPath + "(强制保持)"); LogUtils.d(TAG, String.format("getLastInstance: 已更新最后路径实例,旧实例路径=%s强制保持", oldPath));
return sCachedView; return sCachedView;
} }
@@ -128,12 +129,12 @@ public class MemoryCachedBackgroundView extends BackgroundView {
*/ */
private static void saveLastLoadImagePath(Context context, String imagePath) { private static void saveLastLoadImagePath(Context context, String imagePath) {
if (TextUtils.isEmpty(imagePath) || context == null) { if (TextUtils.isEmpty(imagePath) || context == null) {
LogUtils.w(TAG, "saveLastLoadImagePath路径或上下文为空,跳过保存"); LogUtils.w(TAG, "saveLastLoadImagePath: 路径或上下文为空,跳过保存");
return; return;
} }
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().putString(KEY_LAST_LOAD_IMAGE_PATH, imagePath).apply(); sp.edit().putString(KEY_LAST_LOAD_IMAGE_PATH, imagePath).apply();
LogUtils.d(TAG, "saveLastLoadImagePath已保存最后路径(强制保持) | 路径" + imagePath); LogUtils.d(TAG, String.format("saveLastLoadImagePath: 已保存最后路径(强制保持) | 路径=%s", imagePath));
} }
/** /**
@@ -143,12 +144,12 @@ public class MemoryCachedBackgroundView extends BackgroundView {
*/ */
public static String getLastLoadImagePath(Context context) { public static String getLastLoadImagePath(Context context) {
if (context == null) { if (context == null) {
LogUtils.e(TAG, "getLastLoadImagePath上下文为空返回null"); LogUtils.e(TAG, "getLastLoadImagePath: 上下文为空返回null");
return null; return null;
} }
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String lastPath = sp.getString(KEY_LAST_LOAD_IMAGE_PATH, null); String lastPath = sp.getString(KEY_LAST_LOAD_IMAGE_PATH, null);
LogUtils.d(TAG, "getLastLoadImagePath获取最后路径(强制保持) | 路径" + lastPath); LogUtils.d(TAG, String.format("getLastLoadImagePath: 获取最后路径(强制保持) | 路径=%s", lastPath));
return lastPath; return lastPath;
} }
@@ -157,8 +158,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* 清除当前缓存实例和路径(强制缓存策略:仅日志,不实际清理) * 清除当前缓存实例和路径(强制缓存策略:仅日志,不实际清理)
*/ */
public static void clearCache() { public static void clearCache() {
LogUtils.w(TAG, "clearCache调用(强制缓存策略:不实际清理缓存) | 当前缓存路径" + sCachedImagePath); LogUtils.w(TAG, String.format("clearCache 调用(强制缓存策略:不实际清理缓存) | 当前缓存路径=%s", sCachedImagePath));
LogUtils.d(TAG, "clearCache强制缓存策略生效,未清除任何实例和路径"); LogUtils.d(TAG, "clearCache: 强制缓存策略生效,未清除任何实例和路径");
} }
/** /**
@@ -166,20 +167,20 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @param imagePath 图片路径 * @param imagePath 图片路径
*/ */
public static void removeCache(String imagePath) { public static void removeCache(String imagePath) {
LogUtils.w(TAG, "removeCache调用(强制缓存策略:不实际清理缓存) | 图片路径" + imagePath); LogUtils.w(TAG, String.format("removeCache 调用(强制缓存策略:不实际清理缓存) | 图片路径=%s", imagePath));
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "removeCache图片路径为空,清除失败"); LogUtils.e(TAG, "removeCache: 图片路径为空,清除失败");
return; return;
} }
LogUtils.d(TAG, "removeCache强制缓存策略生效,未清除任何实例和路径"); LogUtils.d(TAG, "removeCache: 强制缓存策略生效,未清除任何实例和路径");
} }
/** /**
* 清除所有缓存(强制缓存策略:仅日志,不实际清理) * 清除所有缓存(强制缓存策略:仅日志,不实际清理)
*/ */
public static void clearAllCache() { public static void clearAllCache() {
LogUtils.w(TAG, "clearAllCache调用(强制缓存策略:不实际清理缓存)"); LogUtils.w(TAG, "clearAllCache 调用(强制缓存策略:不实际清理缓存)");
LogUtils.d(TAG, "clearAllCache强制缓存策略生效未清除任何实例、路径和SP记录"); LogUtils.d(TAG, "clearAllCache: 强制缓存策略生效未清除任何实例、路径和SP记录");
} }
/** /**
@@ -188,7 +189,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
*/ */
public static boolean hasCache() { public static boolean hasCache() {
boolean hasCache = sCachedView != null && !TextUtils.isEmpty(sCachedImagePath); boolean hasCache = sCachedView != null && !TextUtils.isEmpty(sCachedImagePath);
LogUtils.d(TAG, "hasCache缓存存在状态" + hasCache); LogUtils.d(TAG, String.format("hasCache 调用 | 缓存存在状态=%b", hasCache));
return hasCache; return hasCache;
} }
@@ -197,8 +198,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @param context 上下文 * @param context 上下文
*/ */
public static void clearLastLoadImagePath(Context context) { public static void clearLastLoadImagePath(Context context) {
LogUtils.w(TAG, "clearLastLoadImagePath调用强制缓存策略不实际清理SP记录"); LogUtils.w(TAG, "clearLastLoadImagePath 调用强制缓存策略不实际清理SP记录");
LogUtils.d(TAG, "clearLastLoadImagePath强制缓存策略生效未清除SP中最后路径记录"); LogUtils.d(TAG, "clearLastLoadImagePath: 强制缓存策略生效未清除SP中最后路径记录");
} }
// ====================================== 辅助方法:从缓存获取上下文 ====================================== // ====================================== 辅助方法:从缓存获取上下文 ======================================
@@ -208,28 +209,20 @@ public class MemoryCachedBackgroundView extends BackgroundView {
*/ */
private static Context getContextFromCache() { private static Context getContextFromCache() {
Context context = sCachedView != null ? sCachedView.getContext() : null; Context context = sCachedView != null ? sCachedView.getContext() : null;
LogUtils.d(TAG, "getContextFromCache从缓存获取上下文" + context); LogUtils.d(TAG, String.format("getContextFromCache 调用 | 从缓存获取上下文=%s", context));
return context; return context;
} }
// ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ====================================== // ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ======================================
// @Override
// public void loadImage(String imagePath) {
// LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath);
// super.loadImage(imagePath);
// // 保存最后加载路径到SP强制保持不自动删除
// saveLastLoadImagePath(getContext(), imagePath);
// }
@Override @Override
public void loadByBackgroundBean(BackgroundBean bean) { public void loadByBackgroundBean(BackgroundBean bean) {
LogUtils.d(TAG, "loadByBackgroundBean调用 | BackgroundBean" + (bean == null ? "null" : bean.toString())); LogUtils.d(TAG, String.format("loadByBackgroundBean 调用 | BackgroundBean=%s", (bean == null ? "null" : bean.toString())));
super.loadByBackgroundBean(bean); super.loadByBackgroundBean(bean);
} }
@Override @Override
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) { public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
LogUtils.d(TAG, "loadByBackgroundBean调用 | BackgroundBean" + (bean == null ? "null" : bean.toString()) + " | 是否刷新:" + isRefresh); LogUtils.d(TAG, String.format("loadByBackgroundBean 调用 | BackgroundBean=%s | 是否刷新=%b", (bean == null ? "null" : bean.toString()), isRefresh));
super.loadByBackgroundBean(bean, isRefresh); super.loadByBackgroundBean(bean, isRefresh);
} }
@@ -239,7 +232,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @return 实例总数 * @return 实例总数
*/ */
public static int getInstanceCount() { public static int getInstanceCount() {
LogUtils.d(TAG, "getInstanceCount调用 | 当前实例总数" + sInstanceCount); LogUtils.d(TAG, String.format("getInstanceCount 调用 | 当前实例总数=%d", sInstanceCount));
return sInstanceCount; return sInstanceCount;
} }
} }