位图类处理模块重构

This commit is contained in:
2025-12-24 17:28:55 +08:00
parent f771225830
commit 7d50453e34
8 changed files with 301 additions and 164 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Dec 24 12:22:06 HKT 2025 #Wed Dec 24 09:10:57 GMT 2025
stageCount=29 stageCount=29
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.28 publishVersion=15.14.28
buildCount=0 buildCount=57
baseBetaVersion=15.14.29 baseBetaVersion=15.14.29

View File

@@ -12,6 +12,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity; import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.UriUtils; import cc.winboll.studio.powerbell.utils.UriUtils;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
@@ -142,7 +143,8 @@ public class BackgroundPicturePreviewDialog extends Dialog {
} }
// 加载图片到预览视图 // 加载图片到预览视图
mBackgroundView.loadImage(szSrcImage); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(mContext).getCurrentBackgroundBean().getPixelColor();
mBackgroundView.loadImage(nCurrentPixelColor, szSrcImage, true);
LogUtils.d(TAG, "【previewRecivedPicture】图片预览完成文件路径" + szSrcImage); LogUtils.d(TAG, "【previewRecivedPicture】图片预览完成文件路径" + szSrcImage);
} }
} }

View File

@@ -107,7 +107,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
// 图片加载成功,获取文件路径并设置背景 // 图片加载成功,获取文件路径并设置背景
mDownloadSavedPath = (String) msg.obj; mDownloadSavedPath = (String) msg.obj;
LogUtils.d(TAG, String.format("handleMessage: 图片加载成功,保存路径:%s", mDownloadSavedPath)); LogUtils.d(TAG, String.format("handleMessage: 图片加载成功,保存路径:%s", mDownloadSavedPath));
mBackgroundView.loadImage(mDownloadSavedPath); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(mContext).getCurrentBackgroundBean().getPixelColor();
mBackgroundView.loadImage(nCurrentPixelColor, mDownloadSavedPath, true);
break; break;
case MSG_IMAGE_LOAD_FAILED: case MSG_IMAGE_LOAD_FAILED:
// 图片加载失败,设置默认背景 // 图片加载失败,设置默认背景

View File

@@ -14,6 +14,7 @@ import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
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.FileUtils; import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.ImageCropUtils; import cc.winboll.studio.powerbell.utils.ImageCropUtils;
import cc.winboll.studio.powerbell.utils.ImageUtils; import cc.winboll.studio.powerbell.utils.ImageUtils;
@@ -104,7 +105,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview); mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview);
// 创建MemoryCachedBackgroundView单例并添加到布局 // 创建MemoryCachedBackgroundView单例并添加到布局
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, "", false); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, nCurrentPixelColor, "", false);
mllBackgroundView.addView(mMemoryCachedBackgroundView); mllBackgroundView.addView(mMemoryCachedBackgroundView);
LogUtils.d(TAG, "initViewAndEvent内存缓存背景视图实例创建并添加完成"); LogUtils.d(TAG, "initViewAndEvent内存缓存背景视图实例创建并添加完成");
@@ -217,7 +219,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
LogUtils.d(TAG, String.format("handleCropResult裁剪回调处理 | resultCode=%d", resultCode)); LogUtils.d(TAG, String.format("handleCropResult裁剪回调处理 | resultCode=%d", resultCode));
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (isFileValid(mPrivateCropImageFile)) { if (isFileValid(mPrivateCropImageFile)) {
mMemoryCachedBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath()); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
mMemoryCachedBackgroundView.loadImage(nCurrentPixelColor, mPrivateCropImageFile.getAbsolutePath(), true);
LogUtils.d(TAG, String.format("handleCropResult裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath())); LogUtils.d(TAG, String.format("handleCropResult裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath()));
ToastUtils.show("裁剪成功"); ToastUtils.show("裁剪成功");
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true); mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);

View File

@@ -207,25 +207,25 @@ public class MainUnitTestActivity extends AppCompatActivity {
* @param resultCode 裁剪结果码 * @param resultCode 裁剪结果码
*/ */
private void handleCropResult(int resultCode) { private void handleCropResult(int resultCode) {
LogUtils.d(TAG, String.format("handleCropResult裁剪回调处理 | resultCode=%d", resultCode)); // LogUtils.d(TAG, String.format("handleCropResult裁剪回调处理 | resultCode=%d", resultCode));
if (resultCode == RESULT_OK) { // if (resultCode == RESULT_OK) {
if (isFileValid(mPrivateCropImageFile)) { // if (isFileValid(mPrivateCropImageFile)) {
mBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath()); // mBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
LogUtils.d(TAG, String.format("handleCropResult裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath())); // LogUtils.d(TAG, String.format("handleCropResult裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath()));
ToastUtils.show("裁剪成功"); // ToastUtils.show("裁剪成功");
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true); // mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
doubleRefreshPreview(); // doubleRefreshPreview();
} else { // } else {
LogUtils.e(TAG, "handleCropResult裁剪成功但输出文件无效"); // LogUtils.e(TAG, "handleCropResult裁剪成功但输出文件无效");
ToastUtils.show("裁剪失败:输出文件无效"); // ToastUtils.show("裁剪失败:输出文件无效");
} // }
} else if (resultCode == RESULT_CANCELED) { // } else if (resultCode == RESULT_CANCELED) {
LogUtils.d(TAG, "handleCropResult裁剪取消"); // LogUtils.d(TAG, "handleCropResult裁剪取消");
ToastUtils.show("裁剪已取消"); // ToastUtils.show("裁剪已取消");
} else { // } else {
LogUtils.e(TAG, String.format("handleCropResult裁剪失败 | resultCode异常=%d", resultCode)); // LogUtils.e(TAG, String.format("handleCropResult裁剪失败 | resultCode异常=%d", resultCode));
ToastUtils.show("裁剪失败"); // ToastUtils.show("裁剪失败");
} // }
} }
/** /**

View File

@@ -4,7 +4,11 @@ import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
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;
@@ -22,7 +26,7 @@ import java.io.OutputStream;
*/ */
public class ImageUtils { public class ImageUtils {
// ================================== 静态常量区(置顶归类,消除魔法值)================================= // ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = ImageUtils.class.getSimpleName(); 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;
@@ -60,6 +64,75 @@ public class ImageUtils {
} }
} }
public static Bitmap drawBitmapOnSolidBackground(final int bgColor, int originalFrameW, int originalFrameH, Bitmap fgBitmap) {
// 1. 严格参数校验
if (fgBitmap == null || fgBitmap.isRecycled()) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常前景Bitmap为空或已回收");
return null;
}
if (fgBitmap.getWidth() <= 0 || fgBitmap.getHeight() <= 0) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常前景Bitmap尺寸无效");
return null;
}
if (originalFrameW <= 0 || originalFrameH <= 0) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常原画框尺寸无效宽高必须大于0");
return null;
}
// 计算原画框宽高比核心返回位图尺寸严格为originalFrameW×originalFrameH比例自然一致
float frameRatio = (float) originalFrameW / originalFrameH;
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】原画框目标尺寸=%dx%d | 画框比例=%.2f",
originalFrameW, originalFrameH, frameRatio));
// 3. 核心逻辑强制画布尺寸为originalFrameW×originalFrameH满足需求
int extendedCanvasW = originalFrameW;
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) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】创建结果Bitmap失败");
return null;
}
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】结果Bitmap尺寸=%dx%d | 比例=%.2f",
resultBitmap.getWidth(), resultBitmap.getHeight(), (float) resultBitmap.getWidth() / resultBitmap.getHeight()));
// 5. 画布绘制:先画满纯色背景,再画带透明的居中前景
Canvas canvas = new Canvas(resultBitmap);
try {
// 5.1 绘制纯色背景(填满整个目标尺寸画布)
canvas.drawRect(0, 0, extendedCanvasW, extendedCanvasH, new Paint() {{
setColor(bgColor);
setStyle(Paint.Style.FILL);
}});
LogUtils.d(TAG, "【drawBitmapOnSolidBackground】纯色背景绘制完成填满目标尺寸");
// 5.2 计算前景在目标画布内的居中位置
float fgX = (extendedCanvasW - fgBitmap.getWidth()) / 2f;
float fgY = (extendedCanvasH - fgBitmap.getHeight()) / 2f;
// 5.3 绘制前景位图开启透明度支持保留Alpha通道
// Paint fgPaint = new Paint();
// fgPaint.setAlpha(0); // 保持前景自身透明度默认255可根据需求调整
// fgPaint.setAntiAlias(true); // 可选:抗锯齿,让边缘更平滑
// fgPaint.setDither(true); // 可选:抖动,提升色彩显示效果
// canvas.drawBitmap(fgBitmap, fgX, fgY, fgPaint);
// LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】前景位图居中完成 | 位置=(%.1f,%.1f)",
// fgX, fgY));
//
return resultBitmap;
} catch (Exception e) {
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】合成失败", e);
if (resultBitmap != null && !resultBitmap.isRecycled()) {
resultBitmap.recycle();
}
return null;
}
}
// ================================== 核心工具方法(图片质量压缩)================================= // ================================== 核心工具方法(图片质量压缩)=================================
/** /**
* 图片质量压缩JPEG格式压缩后覆盖源文件 * 图片质量压缩JPEG格式压缩后覆盖源文件

View File

@@ -9,6 +9,7 @@ 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;
@@ -16,6 +17,7 @@ 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.ImageUtils;
import java.io.File; import java.io.File;
/** /**
@@ -39,6 +41,10 @@ public class BackgroundView extends RelativeLayout {
private ImageView mIvBackground; // 图片显示控件 private ImageView mIvBackground; // 图片显示控件
// 图片属性 // 图片属性
private float mImageAspectRatio = 1.0f; // 原图宽高比(宽/高) private float mImageAspectRatio = 1.0f; // 原图宽高比(宽/高)
// 当前图片背景
private int mbgColor = 0xFFFFFFFF;
// 当前背景画框尺寸
ViewGroup.LayoutParams mbgLayoutParams;
// ====================================== 构造器Java7兼容 ====================================== // ====================================== 构造器Java7兼容 ======================================
public BackgroundView(Context context) { public BackgroundView(Context context) {
@@ -72,7 +78,7 @@ public class BackgroundView extends RelativeLayout {
// 3. 初始化ImageView // 3. 初始化ImageView
initImageView(); initImageView();
// 4. 初始设置透明背景 // 4. 初始设置透明背景
setDefaultTransparentBackground(); setDefaultEmptyBackground();
LogUtils.d(TAG, "=== initView 完成 ==="); LogUtils.d(TAG, "=== initView 完成 ===");
} }
@@ -86,7 +92,7 @@ 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); //mLlContainer.setBackgroundColor(0x00000000);
this.addView(mLlContainer); this.addView(mLlContainer);
LogUtils.d(TAG, "=== initLinearLayout 完成 ==="); LogUtils.d(TAG, "=== initLinearLayout 完成 ===");
} }
@@ -95,12 +101,12 @@ public class BackgroundView extends RelativeLayout {
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.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT LinearLayout.LayoutParams.MATCH_PARENT
); );
mIvBackground.setLayoutParams(ivParams); mIvBackground.setLayoutParams(ivParams);
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER); mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setBackgroundColor(0x00000000); //mIvBackground.setBackgroundColor(0x00000000);
mLlContainer.addView(mIvBackground); mLlContainer.addView(mIvBackground);
LogUtils.d(TAG, "=== initImageView 完成 ==="); LogUtils.d(TAG, "=== initImageView 完成 ===");
} }
@@ -115,13 +121,17 @@ public class BackgroundView extends RelativeLayout {
// 参数校验 // 参数校验
if (bean == null) { if (bean == null) {
LogUtils.e(TAG, "loadByBackgroundBean: BackgroundBean为空"); LogUtils.e(TAG, "loadByBackgroundBean: BackgroundBean为空");
setDefaultTransparentBackground(); setDefaultEmptyBackground();
return; return;
} }
// 设置图片背景
mbgColor = bean.getPixelColor();
// 判断是否使用背景文件 // 判断是否使用背景文件
if (!bean.isUseBackgroundFile()) { if (!bean.isUseBackgroundFile()) {
LogUtils.d(TAG, "loadByBackgroundBean: 不使用背景文件,设置透明背景"); LogUtils.d(TAG, "loadByBackgroundBean: 不使用背景文件,设置透明背景");
setDefaultTransparentBackground(); setDefaultEmptyBackground();
return; return;
} }
// 获取目标路径 // 获取目标路径
@@ -135,98 +145,140 @@ public class BackgroundView extends RelativeLayout {
LogUtils.e(TAG, "loadByBackgroundBean: 视图控件图片不存在:" + targetPath); LogUtils.e(TAG, "loadByBackgroundBean: 视图控件图片不存在:" + targetPath);
return; return;
} }
loadImage(mbgColor, targetPath, isRefresh);
}
public void loadImage(int bgColor, String imagePath, boolean isRefresh) {
// 3. 隐藏ImageView防止闪烁
mIvBackground.setVisibility(View.GONE);
// 计算画框尺寸
//mbgLayoutParams = adjustImageViewSize();
mbgLayoutParams = mLlContainer.getLayoutParams();
// 刷新逻辑:重新解码原始品质图片并更新缓存 // 刷新逻辑:重新解码原始品质图片并更新缓存
if (isRefresh) { if (isRefresh) {
LogUtils.d(TAG, "loadByBackgroundBean: 刷新图片,重新解码原始品质图片并更新缓存"); LogUtils.d(TAG, "loadByBackgroundBean: 刷新图片,重新解码原始品质图片并更新缓存");
Bitmap newBitmap = decodeOriginalBitmap(targetFile); Bitmap newBitmap = decodeOriginalBitmap(new File(imagePath));
if (newBitmap != null) {
App.sBitmapCacheUtils.cacheBitmap(targetPath, newBitmap); // ======================== 核心集成调用drawBitmapOnSolidBackground合成 ========================
App.sBitmapCacheUtils.increaseRefCount(targetPath); //Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(mbgColor, mbgLayoutParams.width, mbgLayoutParams.height, newBitmap);
LogUtils.d(TAG, "loadByBackgroundBean: 刷新缓存成功,路径=" + targetPath); Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(0xFF112233, mbgLayoutParams.width, mbgLayoutParams.height, newBitmap);
if (combinedBitmap == null) {
LogUtils.e(TAG, "loadImage: 纯色背景合成失败使用原始Bitmap");
combinedBitmap = newBitmap;
} else {
LogUtils.d(TAG, "loadImage: 纯色背景合成成功,尺寸与原始图一致");
// 合成成功后回收原始Bitmap避免重复缓存
if (newBitmap != null && !newBitmap.isRecycled() && newBitmap != combinedBitmap) {
newBitmap.recycle();
LogUtils.d(TAG, "loadImage: 原始Bitmap已回收");
}
}
// ======================== 合成逻辑结束 ========================
if (combinedBitmap != null) {
App.sBitmapCacheUtils.clearAllCache();
App.sBitmapCacheUtils.cacheBitmap(imagePath, combinedBitmap);
App.sBitmapCacheUtils.increaseRefCount(imagePath);
mCurrentCachedPath = imagePath;
LogUtils.d(TAG, "loadByBackgroundBean: 刷新缓存成功,路径=" + imagePath);
} else { } else {
LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + targetPath); LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + imagePath);
} }
} }
// 加载图片 // 加载图片
loadImage(targetPath); Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
setBackgroundColor(bean.getPixelColor()); // 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.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setVisibility(View.VISIBLE);
LogUtils.d(TAG, "=== loadByBackgroundBean 完成 ==="); LogUtils.d(TAG, "=== loadByBackgroundBean 完成 ===");
} }
/** /**
* 改进版:强制保持缓存策略,不自动清理任何缓存,强化引用计数管理,保留图片原始品质 * 改进版:强制保持缓存策略,不自动清理任何缓存,强化引用计数管理,保留图片原始品质
* @param imagePath 图片绝对路径 * @param imagePath 图片绝对路径
*/ */
public void loadImage(String imagePath) { // public void loadImage2(String imagePath) {
LogUtils.d(TAG, "=== loadImage 启动,路径:" + imagePath + " ==="); // LogUtils.d(TAG, "=== loadImage 启动,路径:" + imagePath + "背景色0x%08X ===", mbgColor);
// 1. 路径空校验 // // 1. 路径空校验
if (TextUtils.isEmpty(imagePath)) { // if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "loadImage: 图片路径为空"); // LogUtils.e(TAG, "loadImage: 图片路径为空");
setDefaultTransparentBackground(); // setDefaultEmptyBackground();
return; // return;
} // }
// 2. 文件有效性校验 // // 2. 文件有效性校验
File imageFile = new File(imagePath); // File imageFile = new File(imagePath);
if (!imageFile.exists() || !imageFile.isFile()) { // if (!imageFile.exists() || !imageFile.isFile()) {
LogUtils.e(TAG, "loadImage: 图片文件无效"); // LogUtils.e(TAG, "loadImage: 图片文件无效");
setDefaultTransparentBackground(); // setDefaultEmptyBackground();
return; // return;
} // }
// 3. 隐藏ImageView防止闪烁 //
mIvBackground.setVisibility(View.GONE); // // ======================== 路径判断逻辑(强制缓存版) ========================
// // 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 完成(合成后加载) ===");
// }
// ======================== 路径判断逻辑(强制缓存版) ========================
// 3.1 路径未变化:校验缓存有效性
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);
adjustImageViewSize();
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)) {
setDefaultTransparentBackground();
return;
}
// 5. 获取或解码Bitmap
Bitmap bitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
if (isBitmapValid(bitmap)) {
LogUtils.d(TAG, "loadImage: 从缓存获取有效Bitmap原始品质");
} else {
LogUtils.d(TAG, "loadImage: 缓存未命中,解码原始品质图片");
bitmap = decodeOriginalBitmap(imageFile);
if (bitmap == null) {
LogUtils.e(TAG, "loadImage: 图片解码失败(原始品质)");
ToastUtils.show("图片解码失败,无法加载");
setDefaultTransparentBackground();
return;
}
// 缓存新图片
App.sBitmapCacheUtils.cacheBitmap(imagePath, bitmap);
LogUtils.d(TAG, "loadImage: 新图片缓存成功,路径=" + imagePath);
}
// 6. 引用计数管理
App.sBitmapCacheUtils.increaseRefCount(imagePath);
// 7. 更新当前缓存路径
mCurrentCachedPath = imagePath;
// 8. 设置图片并调整尺寸
mIvBackground.setImageBitmap(bitmap);
adjustImageViewSize();
LogUtils.d(TAG, "=== loadImage 完成 ===");
}
// ====================================== 内部工具方法 ====================================== // ====================================== 内部工具方法 ======================================
/** /**
@@ -299,54 +351,55 @@ public class BackgroundView extends RelativeLayout {
/** /**
* 调整ImageView尺寸保持原图比例 * 调整ImageView尺寸保持原图比例
*/ */
private void adjustImageViewSize() { // private LinearLayout.LayoutParams adjustImageViewSize() {
LogUtils.d(TAG, "=== adjustImageViewSize 启动 ==="); // LogUtils.d(TAG, "=== adjustImageViewSize 启动 ===");
// 空指针校验 // // 空指针校验
if (mLlContainer == null || mIvBackground == null) { // if (mLlContainer == null || mIvBackground == null) {
LogUtils.e(TAG, "adjustImageViewSize: 容器或ImageView未初始化"); // LogUtils.e(TAG, "adjustImageViewSize: 容器或ImageView未初始化");
return; // return null;
} // }
// 获取容器尺寸 // // 获取容器尺寸
int llWidth = mLlContainer.getWidth(); // int llWidth = mLlContainer.getWidth();
int llHeight = mLlContainer.getHeight(); // int llHeight = mLlContainer.getHeight();
if (llWidth == 0 || llHeight == 0) { // if (llWidth == 0 || llHeight == 0) {
LogUtils.w(TAG, "adjustImageViewSize: 容器尺寸未初始化,延迟调整"); // LogUtils.w(TAG, "adjustImageViewSize: 容器尺寸未初始化,延迟调整");
post(new Runnable() { // post(new Runnable() {
@Override // @Override
public void run() { // public void run() {
adjustImageViewSize(); // adjustImageViewSize();
} // }
}); // });
return; // return null;
} // }
// 计算ImageView尺寸 // // 计算ImageView尺寸
int ivWidth, ivHeight; // int ivWidth, ivHeight;
if (mImageAspectRatio >= 1.0f) { // if (mImageAspectRatio >= 1.0f) {
ivWidth = Math.min((int) (llHeight * mImageAspectRatio), llWidth); // ivWidth = Math.min((int) (llHeight * mImageAspectRatio), llWidth);
ivHeight = (int) (ivWidth / mImageAspectRatio); // ivHeight = (int) (ivWidth / mImageAspectRatio);
} else { // } else {
ivHeight = Math.min((int) (llWidth / mImageAspectRatio), llHeight); // ivHeight = Math.min((int) (llWidth / mImageAspectRatio), llHeight);
ivWidth = (int) (ivHeight * mImageAspectRatio); // ivWidth = (int) (ivHeight * mImageAspectRatio);
} // }
// 设置尺寸 // // 设置尺寸
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mIvBackground.getLayoutParams(); // LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mIvBackground.getLayoutParams();
params.width = ivWidth; // params.width = ivWidth;
params.height = ivHeight; // params.height = ivHeight;
mIvBackground.setLayoutParams(params); // mIvBackground.setLayoutParams(params);
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER); // mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setVisibility(View.VISIBLE); // mIvBackground.setVisibility(View.VISIBLE);
LogUtils.d(TAG, "adjustImageViewSize: 尺寸调整完成,宽=" + ivWidth + ",高=" + ivHeight); // LogUtils.d(TAG, "adjustImageViewSize: 尺寸调整完成,宽=" + ivWidth + ",高=" + ivHeight);
LogUtils.d(TAG, "=== adjustImageViewSize 完成 ==="); // LogUtils.d(TAG, "=== adjustImageViewSize 完成 ===");
} // return params;
// }
/** /**
* 设置默认透明背景,仅减少引用计数,不删除缓存 * 设置默认透明背景,仅减少引用计数,不删除缓存
*/ */
private void setDefaultTransparentBackground() { private void setDefaultEmptyBackground() {
LogUtils.d(TAG, "=== setDefaultTransparentBackground 启动 ==="); LogUtils.d(TAG, "=== setDefaultTransparentBackground 启动 ===");
// 清空ImageView // 清空ImageView
mIvBackground.setImageDrawable(null); mIvBackground.setImageDrawable(null);
mIvBackground.setBackgroundColor(0x00000000); //mIvBackground.setBackgroundColor(mbgColor);
mImageAspectRatio = 1.0f; mImageAspectRatio = 1.0f;
// 减少引用计数,不删除缓存 // 减少引用计数,不删除缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) { if (!TextUtils.isEmpty(mCurrentCachedPath)) {
@@ -401,7 +454,9 @@ public class BackgroundView extends RelativeLayout {
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, "onSizeChanged: 尺寸变化,宽=" + w + ",高=" + h + "调整ImageView尺寸");
adjustImageViewSize(); //adjustImageViewSize();
// mbgLayoutParams.width = mLlContainer.getWidth();
// mbgLayoutParams.height = mLlContainer.getHeight();
} }
} }

View File

@@ -6,6 +6,7 @@ import android.text.TextUtils;
import android.util.AttributeSet; 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;
/** /**
* 单实例缓存版背景视图控件基于Java7- 强制缓存版 * 单实例缓存版背景视图控件基于Java7- 强制缓存版
@@ -56,7 +57,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @param isReload 是否强制重新加载图片(路径匹配时仍刷新) * @param isReload 是否强制重新加载图片(路径匹配时仍刷新)
* @return 缓存/新创建的MemoryCachedBackgroundView实例 * @return 缓存/新创建的MemoryCachedBackgroundView实例
*/ */
public static MemoryCachedBackgroundView getInstance(Context context, 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, "【getInstance】调用 | 图片路径:" + imagePath + " | 是否重载:" + isReload);
// 空路径校验 // 空路径校验
if (TextUtils.isEmpty(imagePath)) { if (TextUtils.isEmpty(imagePath)) {
@@ -69,7 +70,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
LogUtils.d(TAG, "【getInstance】路径已缓存当前缓存实例有效"); LogUtils.d(TAG, "【getInstance】路径已缓存当前缓存实例有效");
if (isReload) { if (isReload) {
LogUtils.d(TAG, "【getInstance】强制重载图片 | 路径:" + imagePath); LogUtils.d(TAG, "【getInstance】强制重载图片 | 路径:" + imagePath);
sCachedView.loadImage(imagePath); sCachedView.loadImage(bgColor, imagePath, isReload);
} else { } else {
LogUtils.d(TAG, "【getInstance】使用缓存实例无需重载 | 路径:" + imagePath); LogUtils.d(TAG, "【getInstance】使用缓存实例无需重载 | 路径:" + imagePath);
} }
@@ -81,7 +82,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
String oldPath = sCachedImagePath; String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context); sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = imagePath; sCachedImagePath = imagePath;
sCachedView.loadImage(imagePath); sCachedView.loadImage(bgColor, imagePath, isReload);
LogUtils.d(TAG, "【getInstance】已更新当前缓存实例旧实例路径" + oldPath + "(强制保持)"); LogUtils.d(TAG, "【getInstance】已更新当前缓存实例旧实例路径" + oldPath + "(强制保持)");
return sCachedView; return sCachedView;
} }
@@ -113,7 +114,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
String oldPath = sCachedImagePath; String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context); sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = lastPath; sCachedImagePath = lastPath;
sCachedView.loadImage(lastPath); int nCurrentPixelColor = BackgroundSourceUtils.getInstance(context).getCurrentBackgroundBean().getPixelColor();
sCachedView.loadImage(nCurrentPixelColor, sCachedImagePath, false);
LogUtils.d(TAG, "【getLastInstance】已更新最后路径实例旧实例路径" + oldPath + "(强制保持)"); LogUtils.d(TAG, "【getLastInstance】已更新最后路径实例旧实例路径" + oldPath + "(强制保持)");
return sCachedView; return sCachedView;
} }
@@ -211,13 +213,13 @@ public class MemoryCachedBackgroundView extends BackgroundView {
} }
// ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ====================================== // ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ======================================
@Override // @Override
public void loadImage(String imagePath) { // public void loadImage(String imagePath) {
LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath); // LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath);
super.loadImage(imagePath); // super.loadImage(imagePath);
// 保存最后加载路径到SP强制保持不自动删除 // // 保存最后加载路径到SP强制保持不自动删除
saveLastLoadImagePath(getContext(), imagePath); // saveLastLoadImagePath(getContext(), imagePath);
} // }
@Override @Override
public void loadByBackgroundBean(BackgroundBean bean) { public void loadByBackgroundBean(BackgroundBean bean) {