位图类处理模块重构

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
#Wed Dec 24 12:22:06 HKT 2025
#Wed Dec 24 09:10:57 GMT 2025
stageCount=29
libraryProject=
baseVersion=15.14
publishVersion=15.14.28
buildCount=0
buildCount=57
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.R;
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.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);
}
}

View File

@@ -107,7 +107,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
// 图片加载成功,获取文件路径并设置背景
mDownloadSavedPath = (String) msg.obj;
LogUtils.d(TAG, String.format("handleMessage: 图片加载成功,保存路径:%s", mDownloadSavedPath));
mBackgroundView.loadImage(mDownloadSavedPath);
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(mContext).getCurrentBackgroundBean().getPixelColor();
mBackgroundView.loadImage(nCurrentPixelColor, mDownloadSavedPath, true);
break;
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.R;
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.ImageCropUtils;
import cc.winboll.studio.powerbell.utils.ImageUtils;
@@ -104,7 +105,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview);
// 创建MemoryCachedBackgroundView单例并添加到布局
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, "", false);
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, nCurrentPixelColor, "", false);
mllBackgroundView.addView(mMemoryCachedBackgroundView);
LogUtils.d(TAG, "initViewAndEvent内存缓存背景视图实例创建并添加完成");
@@ -217,7 +219,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
LogUtils.d(TAG, String.format("handleCropResult裁剪回调处理 | resultCode=%d", resultCode));
if (resultCode == RESULT_OK) {
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()));
ToastUtils.show("裁剪成功");
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);

View File

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

View File

@@ -4,7 +4,11 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
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.powerbell.R;
import java.io.File;
@@ -22,7 +26,7 @@ import java.io.OutputStream;
*/
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 int MIN_COMPRESS_QUALITY = 0;
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格式压缩后覆盖源文件

View File

@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
@@ -16,6 +17,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.ImageUtils;
import java.io.File;
/**
@@ -39,6 +41,10 @@ public class BackgroundView extends RelativeLayout {
private ImageView mIvBackground; // 图片显示控件
// 图片属性
private float mImageAspectRatio = 1.0f; // 原图宽高比(宽/高)
// 当前图片背景
private int mbgColor = 0xFFFFFFFF;
// 当前背景画框尺寸
ViewGroup.LayoutParams mbgLayoutParams;
// ====================================== 构造器Java7兼容 ======================================
public BackgroundView(Context context) {
@@ -72,7 +78,7 @@ public class BackgroundView extends RelativeLayout {
// 3. 初始化ImageView
initImageView();
// 4. 初始设置透明背景
setDefaultTransparentBackground();
setDefaultEmptyBackground();
LogUtils.d(TAG, "=== initView 完成 ===");
}
@@ -86,7 +92,7 @@ public class BackgroundView extends RelativeLayout {
mLlContainer.setLayoutParams(llParams);
mLlContainer.setOrientation(LinearLayout.VERTICAL);
mLlContainer.setGravity(android.view.Gravity.CENTER);
mLlContainer.setBackgroundColor(0x00000000);
//mLlContainer.setBackgroundColor(0x00000000);
this.addView(mLlContainer);
LogUtils.d(TAG, "=== initLinearLayout 完成 ===");
}
@@ -95,12 +101,12 @@ public class BackgroundView extends RelativeLayout {
LogUtils.d(TAG, "=== initImageView 启动 ===");
mIvBackground = new ImageView(mContext);
LinearLayout.LayoutParams ivParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
);
mIvBackground.setLayoutParams(ivParams);
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setBackgroundColor(0x00000000);
//mIvBackground.setBackgroundColor(0x00000000);
mLlContainer.addView(mIvBackground);
LogUtils.d(TAG, "=== initImageView 完成 ===");
}
@@ -115,13 +121,17 @@ public class BackgroundView extends RelativeLayout {
// 参数校验
if (bean == null) {
LogUtils.e(TAG, "loadByBackgroundBean: BackgroundBean为空");
setDefaultTransparentBackground();
setDefaultEmptyBackground();
return;
}
// 设置图片背景
mbgColor = bean.getPixelColor();
// 判断是否使用背景文件
if (!bean.isUseBackgroundFile()) {
LogUtils.d(TAG, "loadByBackgroundBean: 不使用背景文件,设置透明背景");
setDefaultTransparentBackground();
setDefaultEmptyBackground();
return;
}
// 获取目标路径
@@ -135,98 +145,140 @@ public class BackgroundView extends RelativeLayout {
LogUtils.e(TAG, "loadByBackgroundBean: 视图控件图片不存在:" + targetPath);
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) {
LogUtils.d(TAG, "loadByBackgroundBean: 刷新图片,重新解码原始品质图片并更新缓存");
Bitmap newBitmap = decodeOriginalBitmap(targetFile);
if (newBitmap != null) {
App.sBitmapCacheUtils.cacheBitmap(targetPath, newBitmap);
App.sBitmapCacheUtils.increaseRefCount(targetPath);
LogUtils.d(TAG, "loadByBackgroundBean: 刷新缓存成功,路径=" + targetPath);
Bitmap newBitmap = decodeOriginalBitmap(new File(imagePath));
// ======================== 核心集成调用drawBitmapOnSolidBackground合成 ========================
//Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(mbgColor, mbgLayoutParams.width, mbgLayoutParams.height, newBitmap);
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 {
LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + targetPath);
LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + imagePath);
}
}
// 加载图片
loadImage(targetPath);
setBackgroundColor(bean.getPixelColor());
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.setScaleType(ImageView.ScaleType.FIT_CENTER);
mIvBackground.setVisibility(View.VISIBLE);
LogUtils.d(TAG, "=== loadByBackgroundBean 完成 ===");
}
}
/**
* 改进版:强制保持缓存策略,不自动清理任何缓存,强化引用计数管理,保留图片原始品质
* @param imagePath 图片绝对路径
*/
public void loadImage(String imagePath) {
LogUtils.d(TAG, "=== loadImage 启动,路径:" + imagePath + " ===");
// 1. 路径空校验
if (TextUtils.isEmpty(imagePath)) {
LogUtils.e(TAG, "loadImage: 图片路径为空");
setDefaultTransparentBackground();
return;
}
// 2. 文件有效性校验
File imageFile = new File(imagePath);
if (!imageFile.exists() || !imageFile.isFile()) {
LogUtils.e(TAG, "loadImage: 图片文件无效");
setDefaultTransparentBackground();
return;
}
// 3. 隐藏ImageView防止闪烁
mIvBackground.setVisibility(View.GONE);
// 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 完成(合成后加载) ===");
// }
// ======================== 路径判断逻辑(强制缓存版) ========================
// 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尺寸保持原图比例
*/
private void adjustImageViewSize() {
LogUtils.d(TAG, "=== adjustImageViewSize 启动 ===");
// 空指针校验
if (mLlContainer == null || mIvBackground == null) {
LogUtils.e(TAG, "adjustImageViewSize: 容器或ImageView未初始化");
return;
}
// 获取容器尺寸
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;
}
// 计算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 完成 ===");
}
// 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 setDefaultTransparentBackground() {
private void setDefaultEmptyBackground() {
LogUtils.d(TAG, "=== setDefaultTransparentBackground 启动 ===");
// 清空ImageView
mIvBackground.setImageDrawable(null);
mIvBackground.setBackgroundColor(0x00000000);
//mIvBackground.setBackgroundColor(mbgColor);
mImageAspectRatio = 1.0f;
// 减少引用计数,不删除缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
@@ -401,7 +454,9 @@ public class BackgroundView extends RelativeLayout {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
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 cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
/**
* 单实例缓存版背景视图控件基于Java7- 强制缓存版
@@ -56,7 +57,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* @param isReload 是否强制重新加载图片(路径匹配时仍刷新)
* @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);
// 空路径校验
if (TextUtils.isEmpty(imagePath)) {
@@ -69,7 +70,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
LogUtils.d(TAG, "【getInstance】路径已缓存当前缓存实例有效");
if (isReload) {
LogUtils.d(TAG, "【getInstance】强制重载图片 | 路径:" + imagePath);
sCachedView.loadImage(imagePath);
sCachedView.loadImage(bgColor, imagePath, isReload);
} else {
LogUtils.d(TAG, "【getInstance】使用缓存实例无需重载 | 路径:" + imagePath);
}
@@ -81,7 +82,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = imagePath;
sCachedView.loadImage(imagePath);
sCachedView.loadImage(bgColor, imagePath, isReload);
LogUtils.d(TAG, "【getInstance】已更新当前缓存实例旧实例路径" + oldPath + "(强制保持)");
return sCachedView;
}
@@ -113,7 +114,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
String oldPath = sCachedImagePath;
sCachedView = new MemoryCachedBackgroundView(context);
sCachedImagePath = lastPath;
sCachedView.loadImage(lastPath);
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(context).getCurrentBackgroundBean().getPixelColor();
sCachedView.loadImage(nCurrentPixelColor, sCachedImagePath, false);
LogUtils.d(TAG, "【getLastInstance】已更新最后路径实例旧实例路径" + oldPath + "(强制保持)");
return sCachedView;
}
@@ -211,13 +213,13 @@ public class MemoryCachedBackgroundView extends BackgroundView {
}
// ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ======================================
@Override
public void loadImage(String imagePath) {
LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath);
super.loadImage(imagePath);
// 保存最后加载路径到SP强制保持不自动删除
saveLastLoadImagePath(getContext(), imagePath);
}
// @Override
// public void loadImage(String imagePath) {
// LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath);
// super.loadImage(imagePath);
// // 保存最后加载路径到SP强制保持不自动删除
// saveLastLoadImagePath(getContext(), imagePath);
// }
@Override
public void loadByBackgroundBean(BackgroundBean bean) {