20251201_023218_404

This commit is contained in:
2025-12-01 02:32:28 +08:00
parent 3c3bcc4ee4
commit 9b010df881
2 changed files with 148 additions and 131 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sun Nov 30 18:04:35 GMT 2025
#Sun Nov 30 18:31:19 GMT 2025
stageCount=13
libraryProject=
baseVersion=15.11
publishVersion=15.11.12
buildCount=13
buildCount=15
baseBetaVersion=15.11.13

View File

@@ -528,131 +528,133 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
}
}
/**
* 保存剪裁后的Bitmap彻底修复路径拼接+权限+解析异常)
*/
private void saveCropBitmap(Bitmap bitmap) {
if (bitmap == null || bitmap.isRecycled()) {
ToastUtils.show("剪裁图片为空或已回收");
// 清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
}
return;
}
* 保存剪裁后的Bitmap彻底修复路径拼接+权限+解析异常)
*/
private void saveCropBitmap(Bitmap bitmap) {
if (bitmap == null || bitmap.isRecycled()) {
ToastUtils.show("剪裁图片为空或已回收");
// 清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
}
return;
}
// 内存优化:大图片自动缩放(保持原逻辑)
Bitmap scaledBitmap = bitmap;
if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB
float scale = 1.0f;
while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) {
scale -= 0.2f; // 每次缩小20%
if (scale < 0.2f) break; // 最小缩放到20%
scaledBitmap = scaleBitmap(scaledBitmap, scale);
}
if (scaledBitmap != bitmap) {
bitmap.recycle(); // 回收原Bitmap
}
}
// 内存优化:大图片自动缩放(保持原逻辑)
Bitmap scaledBitmap = bitmap;
if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB
float scale = 1.0f;
while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) {
scale -= 0.2f; // 每次缩小20%
if (scale < 0.2f) break; // 最小缩放到20%
scaledBitmap = scaleBitmap(scaledBitmap, scale);
}
if (scaledBitmap != bitmap) {
bitmap.recycle(); // 回收原Bitmap
}
}
// 核心修复1正确获取保存路径(直接使用完整路径,避免重复拼接
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
String scaledCompressFilePath = utils.getPreviewBackgroundScaledCompressFilePath(); // 完整路径(无嵌套)
File fScaledCompressBitmapFile = new File(scaledCompressFilePath);
// 核心修复1统一保存路径到_mSourceCroppedFile最终目标文件
File fScaledCompressBitmapFile = _mSourceCroppedFile;
String scaledCompressFilePath = fScaledCompressBitmapFile.getAbsolutePath();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
// 确保保存目录存在(避免路径无效)
File parentDir = fScaledCompressBitmapFile.getParentFile();
if (!parentDir.exists()) {
if (!parentDir.mkdirs()) {
ToastUtils.show("无法创建保存目录:" + parentDir.getAbsolutePath());
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
// 确保保存目录存在(避免路径无效)
File parentDir = fScaledCompressBitmapFile.getParentFile();
if (!parentDir.exists()) {
if (!parentDir.mkdirs()) {
ToastUtils.show("无法创建保存目录:" + parentDir.getAbsolutePath());
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
// 优化:检查文件权限(确保可写)
if (fScaledCompressBitmapFile.exists()) {
if (!fScaledCompressBitmapFile.canWrite()) {
if (!fScaledCompressBitmapFile.delete()) {
ToastUtils.show("无法删除旧文件(权限不足):" + fScaledCompressBitmapFile.getPath());
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
}
// 优化:检查文件权限(确保可写)
if (fScaledCompressBitmapFile.exists()) {
if (!fScaledCompressBitmapFile.canWrite()) {
if (!fScaledCompressBitmapFile.delete()) {
ToastUtils.show("无法删除旧文件(权限不足):" + fScaledCompressBitmapFile.getPath());
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
}
FileOutputStream fos = null;
try {
// 修复2设置文件可写权限避免写入失败
fScaledCompressBitmapFile.setWritable(true, false);
fos = new FileOutputStream(fScaledCompressBitmapFile);
// 压缩保存80%质量,平衡清晰度和大小
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
fos.flush();
if (success) {
ToastUtils.show("图片压缩保存成功");
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
// 修复3同步裁剪后文件名到预览Bean仅传文件名避免路径污染
String cropFileName = fScaledCompressBitmapFile.getName();
previewBean.setBackgroundFileName(cropFileName);
previewBean.setIsUseBackgroundFile(true); // 强制启用背景图
previewBean.setIsUseScaledCompress(true);
utils.saveSettings(); // 持久化配置
FileOutputStream fos = null;
try {
// 修复2设置文件可写权限避免写入失败
fScaledCompressBitmapFile.setWritable(true, false);
fos = new FileOutputStream(fScaledCompressBitmapFile);
// 核心修复3根据目标文件名自动适配压缩格式兼容JPEG/PNG
Bitmap.CompressFormat compressFormat = _mSourceCroppedFileName.endsWith(".png")
? Bitmap.CompressFormat.PNG
: Bitmap.CompressFormat.JPEG;
// 压缩保存80%质量,平衡清晰度和大小)
boolean success = scaledBitmap.compress(compressFormat, 80, fos);
fos.flush();
if (success) {
ToastUtils.show("图片压缩保存成功");
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
// 修复4同步目标文件名到预览Bean确保后续读取正确
previewBean.setBackgroundFileName(_mSourceCroppedFileName);
previewBean.setIsUseBackgroundFile(true); // 强制启用背景图
previewBean.setIsUseScaledCompress(true);
utils.saveSettings(); // 持久化配置
// 清理临时文件(双重保障
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪成功,清理临时文件:" + _mSourceCropTempFile.getPath());
}
// 核心修复5保存成功后再清理临时文件避免提前删除导致读取失败
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪成功,清理临时文件:" + _mSourceCropTempFile.getPath());
}
// 刷新预览视图(确保裁剪图实时显示)
bvPreviewBackground.reloadPreviewBackground();
// 刷新预览视图(确保裁剪图实时显示)
bvPreviewBackground.reloadPreviewBackground();
} else {
ToastUtils.show("图片压缩保存失败Bitmap压缩异常");
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
previewBean.setIsUseScaledCompress(false);
utils.saveSettings();
// 清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪失败,清理临时文件:" + _mSourceCropTempFile.getPath());
}
// 刷新原始预览图
bvPreviewBackground.reloadPreviewBackground();
}
} catch (FileNotFoundException e) {
LogUtils.e(TAG, "文件未找到:" + e.getMessage() + ",保存路径:" + fScaledCompressBitmapFile.getPath());
ToastUtils.show("保存失败:文件路径无效");
// 异常时清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
}
} catch (IOException e) {
LogUtils.e(TAG, "写入异常:" + e.getMessage());
ToastUtils.show("保存失败:无写入权限或文件损坏");
// 异常时清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
}
} finally {
// 关闭流(避免资源泄漏)
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogUtils.e(TAG, "流关闭异常" + e);
ToastUtils.show("流关闭异常:" + e.getMessage());
}
}
// 回收Bitmap避免内存泄漏
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
}
}
} else {
ToastUtils.show("图片压缩保存失败Bitmap压缩异常");
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
previewBean.setIsUseScaledCompress(false);
utils.saveSettings();
// 清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪失败,清理临时文件:" + _mSourceCropTempFile.getPath());
}
// 刷新原始预览图
bvPreviewBackground.reloadPreviewBackground();
}
} catch (FileNotFoundException e) {
LogUtils.e(TAG, "文件未找到:" + e.getMessage() + ",保存路径:" + scaledCompressFilePath);
ToastUtils.show("保存失败:文件路径无效");
// 异常时清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
}
} catch (IOException e) {
LogUtils.e(TAG, "写入异常:" + e.getMessage());
ToastUtils.show("保存失败:无写入权限或文件损坏");
// 异常时清理临时文件
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
}
} finally {
// 关闭流(避免资源泄漏)
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogUtils.e(TAG, "流关闭异常" + e);
ToastUtils.show("流关闭异常:" + e.getMessage());
}
}
// 回收Bitmap避免内存泄漏
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
}
}
/**
* 缩放Bitmap
@@ -695,6 +697,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -710,8 +713,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
// 核心修复对ACTION_GET_CONTENT返回的Uri添加持久化权限Android 4.4+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getContentResolver().takePersistableUriPermission(
selectedImage,
Intent.FLAG_GRANT_READ_URI_PERMISSION
selectedImage,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
}
@@ -790,12 +793,29 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
Bitmap cropBitmap = null;
// 核心修复优先读取裁剪临时文件放弃data.getParcelableExtra避免缩略图
if (_mSourceCropTempFile.exists() && _mSourceCropTempFile.length() > 0) {
LogUtils.d(TAG, String.format("_mSourceCropTempFile 信息:路径=%s , 大小=%d bytes",
LogUtils.d(TAG, String.format("_mSourceCropTempFile 信息:路径=%s , 大小=%d bytes",
_mSourceCropTempFile.getPath(), _mSourceCropTempFile.length()));
// 优化Bitmap解析选项避免OOM和损坏图片解析失败)
// 核心修复:优化Bitmap解析选项自动适配格式+防止OOM+避免损坏图片解析失败)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565; // 省内存仅RGB无透明通道
options.inSampleSize = 1; // 不缩放(保证清晰度)
// 第一步仅获取图片信息不加载Bitmap避免OOM
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(_mSourceCropTempFile.getPath(), options);
// 自动适配图片格式PNG用ARGB_8888JPEG用RGB_565省内存
String imageMimeType = options.outMimeType;
options.inPreferredConfig = (imageMimeType != null && imageMimeType.contains("png"))
? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
// 自动计算采样率防止大图片OOM最大边长限制为2048
int maxImageSize = 2048;
int sampleRate = 1;
while (options.outWidth / sampleRate > maxImageSize || options.outHeight / sampleRate > maxImageSize) {
sampleRate *= 2;
}
options.inSampleSize = sampleRate;
// 第二步正式加载Bitmap
options.inJustDecodeBounds = false;
cropBitmap = BitmapFactory.decodeFile(_mSourceCropTempFile.getPath(), options);
} else {
@@ -805,7 +825,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
// 检查解析后的Bitmap是否有效
if (cropBitmap != null && !cropBitmap.isRecycled()) {
saveCropBitmap(cropBitmap); // 调用保存方法(内含修复逻辑)
saveCropBitmap(cropBitmap); // 调用修复后的保存方法
} else {
ToastUtils.show("获取剪裁图片失败Bitmap解析异常");
// 清理无效临时文件
@@ -829,11 +849,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
_mSourceCropTempFile.delete();
}
} finally {
// 裁剪流程结束,强制清理临时文件(双重保障,避免残留
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
LogUtils.d(TAG, "裁剪流程结束,强制清理临时文件:" + _mSourceCropTempFile.getPath());
}
// 核心修复移除临时文件清理代码已移至saveCropBitmap成功后清理
LogUtils.d(TAG, "裁剪流程结束");
}
} else if (resultCode != RESULT_OK) {
LogUtils.d(TAG, "操作取消或失败requestCode: " + requestCode);
@@ -844,7 +861,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, "操作取消/失败,清理临时文件:" + _mSourceCropTempFile.getPath());
}
}
}
}
/**
* 检查类型是否为图片