20251211_130438_907

This commit is contained in:
2025-12-11 13:04:44 +08:00
parent 220aa9dbfb
commit fd556fd06f
6 changed files with 376 additions and 242 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Dec 11 00:57:37 GMT 2025 #Thu Dec 11 04:59:14 GMT 2025
stageCount=15 stageCount=15
libraryProject= libraryProject=
baseVersion=15.12 baseVersion=15.12
publishVersion=15.12.14 publishVersion=15.12.14
buildCount=13 buildCount=21
baseBetaVersion=15.12.15 baseBetaVersion=15.12.15

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

View File

@@ -47,6 +47,7 @@ import cc.winboll.studio.powerbell.utils.ImageCropUtils;
import cc.winboll.studio.powerbell.utils.PermissionUtils; import cc.winboll.studio.powerbell.utils.PermissionUtils;
import cc.winboll.studio.powerbell.utils.UriUtil; import cc.winboll.studio.powerbell.utils.UriUtil;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
import cc.winboll.studio.powerbell.utils.AssetsCopyUtils;
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener { public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
@@ -111,10 +112,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
mBgSourceUtils.setCurrentSourceToPreview(); mBgSourceUtils.setCurrentSourceToPreview();
} }
//Uri uriSelectedImage = UriUtil.getUriForFile(this, new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath())); mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(mBgSourceUtils.getPreviewBackgroundBean());
File fTestSourceExist = new File(mBgSourceUtils.getCurrentBackgroundBean().getBackgroundFilePath());
boolean isCreateNewPreviewBean = !fTestSourceExist.exists();
mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(isCreateNewPreviewBean, mBgSourceUtils.getPreviewBackgroundBean());
doubleRefreshPreview(); doubleRefreshPreview();
LogUtils.d(TAG, "【初始化】BackgroundSettingsActivity 初始化完成"); LogUtils.d(TAG, "【初始化】BackgroundSettingsActivity 初始化完成");
} }
@@ -437,7 +435,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
} }
Bitmap photoBitmap = getTakePhotoBitmap(data); Bitmap photoBitmap = getTakePhotoBitmap(data);
if (photoBitmap != null && !photoBitmap.isRecycled()) { if (isBitmapValid(photoBitmap)) {
mBgSourceUtils.compressQualityToRecivedPicture(photoBitmap); mBgSourceUtils.compressQualityToRecivedPicture(photoBitmap);
} else { } else {
ToastUtils.show("拍照图片为空"); ToastUtils.show("拍照图片为空");
@@ -462,7 +460,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
if (mfTakePhoto != null && mfTakePhoto.exists()) { if (mfTakePhoto != null && mfTakePhoto.exists()) {
LogUtils.d(TAG, "【拍照Bitmap解析】从文件解析"); LogUtils.d(TAG, "【拍照Bitmap解析】从文件解析");
Bitmap photoBitmap = parseCropTempFileToBitmap(mfTakePhoto); Bitmap photoBitmap = parseCropTempFileToBitmap(mfTakePhoto);
if (photoBitmap != null && !photoBitmap.isRecycled()) { if (isBitmapValid(photoBitmap)) {
LogUtils.d(TAG, "【拍照Bitmap解析】成功"); LogUtils.d(TAG, "【拍照Bitmap解析】成功");
return photoBitmap; return photoBitmap;
} else { } else {
@@ -475,7 +473,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
if (data != null) { if (data != null) {
try { try {
Bitmap thumbnailBitmap = (Bitmap) data.getParcelableExtra("data"); Bitmap thumbnailBitmap = (Bitmap) data.getParcelableExtra("data");
if (thumbnailBitmap != null && !thumbnailBitmap.isRecycled()) { if (isBitmapValid(thumbnailBitmap)) {
LogUtils.d(TAG, "【拍照Bitmap解析】从Intent获取成功"); LogUtils.d(TAG, "【拍照Bitmap解析】从Intent获取成功");
return thumbnailBitmap; return thumbnailBitmap;
} else { } else {
@@ -515,32 +513,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, "【选图权限】已添加持久化权限"); LogUtils.d(TAG, "【选图权限】已添加持久化权限");
} }
// 2. 强制拷贝到应用私有目录(彻底规避系统虚拟路径问题) // 2. 同步到预览 Bean 并启动裁剪
// String privateImagePath = copyUriToPrivateDir(selectedImage);
// if (TextUtils.isEmpty(privateImagePath)) {
// ToastUtils.show("系统图片路径无效,拷贝失败");
// LogUtils.e(TAG, "【选图校验】系统Uri拷贝失败Uri=" + selectedImage.toString());
// return;
// }
//
// // 3. 严格校验私有目录文件有效性
// File srcFile = new File(privateImagePath);
// if (srcFile == null
// || !srcFile.exists()
// || !srcFile.isFile()
// || srcFile.length() <= 0) {
// ToastUtils.show("系统图片文件无效");
// LogUtils.e(TAG, "【选图校验】私有目录文件无效,路径=" + privateImagePath);
// // 清理无效文件
// if (srcFile != null && srcFile.exists()) {
// srcFile.delete();
// }
// return;
// }
//LogUtils.d(TAG, "【选图校验】系统图片校验通过,私有路径:" + privateImagePath);
// 4. 同步到预览 Bean 并启动裁剪
if (putUriFileToPreviewSource(selectedImage)) { if (putUriFileToPreviewSource(selectedImage)) {
LogUtils.d(TAG, "【选图同步】路径绑定完成"); LogUtils.d(TAG, "【选图同步】路径绑定完成");
mBitmapCache.removeCachedBitmap(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()); mBitmapCache.removeCachedBitmap(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath());
@@ -558,7 +531,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
} }
boolean putUriFileToPreviewSource(Uri srcUriFile) { boolean putUriFileToPreviewSource(Uri srcUriFile) {
File srcFile = new File(UriUtil.getFilePathFromUri(this, srcUriFile)); String filePath = UriUtil.getFilePathFromUri(this, srcUriFile);
// 关键修复:校验路径是否为空
if (TextUtils.isEmpty(filePath)) {
LogUtils.e(TAG, "putUriFileToPreviewSource: Uri解析路径为空");
return false;
}
File srcFile = new File(filePath);
return putUriFileToPreviewSource(srcFile); return putUriFileToPreviewSource(srcFile);
} }
@@ -588,16 +567,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
float systemFileRatio = getRatioFromSystemCropFile(cropTempFile); float systemFileRatio = getRatioFromSystemCropFile(cropTempFile);
if (systemFileRatio > 0) { if (systemFileRatio > 0) {
Bitmap cropBitmap = parseCropTempFileToBitmap(cropTempFile); Bitmap cropBitmap = parseCropTempFileToBitmap(cropTempFile);
if (cropBitmap != null && !cropBitmap.isRecycled()) { // 校验解析后的Bitmap是否有效
if (isBitmapValid(cropBitmap)) {
Bitmap scaledCropBitmap = adjustBitmapToFinalRatio(cropBitmap, systemFileRatio); Bitmap scaledCropBitmap = adjustBitmapToFinalRatio(cropBitmap, systemFileRatio);
// 仅当新Bitmap生成成功时才保存并回收
if (isBitmapValid(scaledCropBitmap)) {
saveScaledBitmapToFile(scaledCropBitmap, cropTempFile); saveScaledBitmapToFile(scaledCropBitmap, cropTempFile);
if (scaledCropBitmap != cropBitmap && !scaledCropBitmap.isRecycled()) {
scaledCropBitmap.recycle(); scaledCropBitmap.recycle();
} }
if (!cropBitmap.isRecycled()) {
cropBitmap.recycle(); cropBitmap.recycle();
} } else {
LogUtils.e(TAG, "handleCropImageResult: 裁剪Bitmap解析无效");
} }
} }
@@ -638,11 +618,21 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
return systemRatio; return systemRatio;
} }
/**
* 校验 Bitmap 是否有效(未被回收且不为空)
* @param bitmap 待校验的 Bitmap
* @return true=有效 false=无效
*/
private boolean isBitmapValid(Bitmap bitmap) {
return bitmap != null && !bitmap.isRecycled();
}
private Bitmap adjustBitmapToFinalRatio(Bitmap originalBitmap, float finalCropRatio) { private Bitmap adjustBitmapToFinalRatio(Bitmap originalBitmap, float finalCropRatio) {
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整比例"); LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整比例");
if (originalBitmap == null || originalBitmap.isRecycled() || finalCropRatio <= 0) { // 增加 Bitmap 有效性校验
if (!isBitmapValid(originalBitmap) || finalCropRatio <= 0) {
LogUtils.e(TAG, "adjustBitmapToFinalRatio: 参数无效"); LogUtils.e(TAG, "adjustBitmapToFinalRatio: 参数无效");
return originalBitmap; return null; // 直接返回null避免传递无效Bitmap
} }
int originalWidth = originalBitmap.getWidth(); int originalWidth = originalBitmap.getWidth();
@@ -650,8 +640,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
float originalRatio = (float) originalWidth / originalHeight; float originalRatio = (float) originalWidth / originalHeight;
if (Math.abs(originalRatio - finalCropRatio) < 0.001f) { if (Math.abs(originalRatio - finalCropRatio) < 0.001f) {
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 比例一致"); LogUtils.d(TAG, "adjustBitmapToFinalRatio: 比例一致,生成副本");
return originalBitmap; // 关键修复不返回原Bitmap而是生成副本避免原Bitmap被回收后失效
return originalBitmap.copy(originalBitmap.getConfig(), false);
} }
int targetWidth, targetHeight; int targetWidth, targetHeight;
@@ -665,6 +656,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
targetWidth = Math.round(targetHeight * finalCropRatio); targetWidth = Math.round(targetHeight * finalCropRatio);
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight); LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight);
try {
Bitmap adjustedBitmap = Bitmap.createBitmap( Bitmap adjustedBitmap = Bitmap.createBitmap(
originalBitmap, originalBitmap,
(originalWidth - targetWidth) / 2, (originalWidth - targetWidth) / 2,
@@ -672,13 +664,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
targetWidth, targetWidth,
targetHeight targetHeight
); );
return adjustedBitmap; return adjustedBitmap;
} catch (OutOfMemoryError e) {
LogUtils.e(TAG, "adjustBitmapToFinalRatio: OOM异常");
return null;
}
} }
private void saveScaledBitmapToFile(Bitmap bitmap, File targetFile) { private void saveScaledBitmapToFile(Bitmap bitmap, File targetFile) {
LogUtils.d(TAG, "saveScaledBitmapToFile: 保存图片"); LogUtils.d(TAG, "saveScaledBitmapToFile: 保存图片");
if (bitmap == null || bitmap.isRecycled() || targetFile == null) { if (!isBitmapValid(bitmap) || targetFile == null) {
LogUtils.e(TAG, "saveScaledBitmapToFile: 参数无效"); LogUtils.e(TAG, "saveScaledBitmapToFile: 参数无效");
return; return;
} }
@@ -735,7 +730,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
Bitmap cropBitmap = null; Bitmap cropBitmap = null;
try { try {
cropBitmap = BitmapFactory.decodeFile(cropTempFile.getAbsolutePath(), options); cropBitmap = BitmapFactory.decodeFile(cropTempFile.getAbsolutePath(), options);
if (cropBitmap == null || cropBitmap.isRecycled()) { if (!isBitmapValid(cropBitmap)) {
LogUtils.e(TAG, "parseCropTempFileToBitmap: 解析失败"); LogUtils.e(TAG, "parseCropTempFileToBitmap: 解析失败");
return null; return null;
} }
@@ -754,8 +749,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
private void doubleRefreshPreview() { private void doubleRefreshPreview() {
LogUtils.d(TAG, "【双重刷新】开始"); LogUtils.d(TAG, "【双重刷新】开始");
// 增加非空校验
if (mBgSourceUtils == null || mBackgroundView == null || isFinishing()) {
LogUtils.w(TAG, "【双重刷新】跳过对象为空或Activity已结束");
return;
}
// 清空缓存工具类的旧数据 // 清空缓存工具类的旧数据
if (mBgSourceUtils != null) {
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
if (previewBean != null && previewBean.isUseBackgroundFile()) { if (previewBean != null && previewBean.isUseBackgroundFile()) {
String bgPath = previewBean.isUseBackgroundScaledCompressFile() String bgPath = previewBean.isUseBackgroundScaledCompressFile()
@@ -764,28 +764,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
mBitmapCache.removeCachedBitmap(bgPath); mBitmapCache.removeCachedBitmap(bgPath);
LogUtils.d(TAG, "【双重刷新】已清空工具类缓存:" + bgPath); LogUtils.d(TAG, "【双重刷新】已清空工具类缓存:" + bgPath);
} }
}
// 清空 BackgroundView 自身的 Bitmap 引用
// if (mBackgroundView != null) {
// if (mBackgroundView instanceof ImageView) {
// ((ImageView) mBackgroundView).setImageBitmap(null);
// }
// Drawable drawable = mBackgroundView.getBackground();
// if (drawable != null) {
// drawable.setCallback(null);
// mBackgroundView.setBackground(null);
// }
// LogUtils.d(TAG, "【双重刷新】已清空控件 Bitmap 引用");
// }
// 重新加载最新数据 // 重新加载最新数据
if (mBackgroundView != null && !isFinishing()) { try {
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean()); mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
LogUtils.d(TAG, "【双重刷新】第一重完成"); LogUtils.d(TAG, "【双重刷新】第一重完成");
} else { } catch (Exception e) {
LogUtils.w(TAG, "【双重刷新】跳过"); LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
return; return;
} }
@@ -793,10 +779,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
if (mBackgroundView != null && !isFinishing()) { if (mBackgroundView != null && !isFinishing() && mBgSourceUtils != null) {
try {
mBgSourceUtils.loadSettings(); mBgSourceUtils.loadSettings();
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean()); mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
LogUtils.d(TAG, "【双重刷新】第二重完成"); LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {
LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
}
} }
} }
}, 200); }, 200);
@@ -863,62 +853,57 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
/** /**
* 解析Uri到真实文件路径兼容所有Android版本 * 解析Uri到真实文件路径兼容所有Android版本
* @param uri 图片的Content Uri
* @return 真实文件路径 / null
*/ */
// private String getRealPathFromUri(Uri uri) { private String getRealPathFromUri(Uri uri) {
// String path = null; String path = null;
// String[] projection = {MediaStore.Images.Media.DATA}; String[] projection = {MediaStore.Images.Media.DATA};
// Cursor cursor = getContentResolver().query(uri, projection, null, null, null); Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
// if (cursor != null) { if (cursor != null) {
// if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
// int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
// path = cursor.getString(columnIndex); path = cursor.getString(columnIndex);
// } }
// cursor.close(); cursor.close();
// } }
// // 针对Android 10+沙箱限制,拷贝到私有目录 // 针对Android 10+沙箱限制,拷贝到私有目录
// if (TextUtils.isEmpty(path)) { if (TextUtils.isEmpty(path)) {
// path = copyUriToPrivateDir(uri);
// path = copyUriToPrivateDir(uri); }
// } return path;
// return path; }
// }
/** /**
* 将Uri对应的图片拷贝到应用私有临时目录 * 将Uri对应的图片拷贝到应用私有临时目录
* @param uri 图片Uri
* @return 拷贝后的文件路径 / null
*/ */
// private String copyUriToPrivateDir(Uri uri) { private String copyUriToPrivateDir(Uri uri) {
// try { try {
// InputStream inputStream = getContentResolver().openInputStream(uri); InputStream inputStream = getContentResolver().openInputStream(uri);
// if (inputStream == null) { if (inputStream == null) {
// return null; return null;
// } }
// File tempDir = new File(App.getTempDirPath()); File tempDir = new File(App.getTempDirPath());
// if (!tempDir.exists()) { if (!tempDir.exists()) {
// tempDir.mkdirs(); tempDir.mkdirs();
// } }
// String fileName = "select_temp_" + System.currentTimeMillis() + ".jpg"; String fileName = "select_temp_" + System.currentTimeMillis() + ".jpg";
// File destFile = new File(tempDir, fileName); File destFile = new File(tempDir, fileName);
//
// OutputStream outputStream = new FileOutputStream(destFile); OutputStream outputStream = new FileOutputStream(destFile);
// byte[] buffer = new byte[1024 * 4]; byte[] buffer = new byte[1024 * 4];
// int len; int len;
// while ((len = inputStream.read(buffer)) != -1) { while ((len = inputStream.read(buffer)) != -1) {
// outputStream.write(buffer, 0, len); outputStream.write(buffer, 0, len);
// } }
// outputStream.flush(); outputStream.flush();
// inputStream.close(); inputStream.close();
// outputStream.close(); outputStream.close();
//
// LogUtils.d(TAG, "【选图拷贝】文件已拷贝到私有目录:" + destFile.getAbsolutePath()); LogUtils.d(TAG, "【选图拷贝】文件已拷贝到私有目录:" + destFile.getAbsolutePath());
// return destFile.getAbsolutePath(); return destFile.getAbsolutePath();
// } catch (IOException e) { } catch (IOException e) {
// LogUtils.e(TAG, "【选图拷贝】异常:" + e.getMessage()); LogUtils.e(TAG, "【选图拷贝】异常:" + e.getMessage());
// return null; return null;
// } }
// } }
} }

View File

@@ -0,0 +1,122 @@
package cc.winboll.studio.powerbell.utils;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/11 09:14
* @Describe Assets 目录拷贝工具类
* 支持将 assets/images/ 下所有文件、子目录拷贝到指定路径
*/
public class AssetsCopyUtils {
public static final String TAG = "AssetsCopyUtils";
private static final int BUFFER_SIZE = 1024 * 8;
/**
* 拷贝 assets/images/ 目录到指定目标目录
* @param context 上下文
* @param targetDirPath 目标目录完整路径(如 /sdcard/PowerBell/assets_images
* @return 拷贝是否成功
*/
public static boolean copyAssetsImagesToDir(Context context, String targetDirPath) {
// 拷贝 assets/images 根目录
return copyAssetsDirToDir(context, "images", targetDirPath);
}
/**
* 递归拷贝 assets 下指定目录到目标目录
* @param context 上下文
* @param assetsDir assets 下的源目录(如 "images"、"images/subdir"
* @param targetDirPath 目标目录完整路径
* @return 拷贝是否成功
*/
public static boolean copyAssetsDirToDir(Context context, String assetsDir, String targetDirPath) {
File targetDir = new File(targetDirPath);
// 创建目标目录(含多级父目录)
if (!targetDir.exists() && !targetDir.mkdirs()) {
Log.e(TAG, "创建目标目录失败:" + targetDirPath);
return false;
}
try {
// 获取 assets 目录下的文件/子目录列表
String[] fileList = context.getAssets().list(assetsDir);
if (fileList == null || fileList.length == 0) {
Log.d(TAG, "assets 目录为空:" + assetsDir);
return true;
}
for (String fileName : fileList) {
String assetsFilePath = assetsDir + File.separator + fileName;
String targetFilePath = targetDirPath + File.separator + fileName;
// 判断当前项是文件还是子目录
String[] subFileList = context.getAssets().list(assetsFilePath);
if (subFileList != null && subFileList.length > 0) {
// 是子目录,递归拷贝
if (!copyAssetsDirToDir(context, assetsFilePath, targetFilePath)) {
return false;
}
} else {
// 是文件,直接拷贝
if (!copyAssetsFileToDir(context, assetsFilePath, targetFilePath)) {
return false;
}
}
}
Log.d(TAG, "assets 目录拷贝完成:" + assetsDir + " -> " + targetDirPath);
return true;
} catch (IOException e) {
Log.e(TAG, "拷贝 assets 目录异常:" + e.getMessage());
return false;
}
}
/**
* 拷贝 assets 下单个文件到指定路径
* @param context 上下文
* @param assetsFilePath assets 下的文件路径(如 "images/cloud.png"
* @param targetFilePath 目标文件完整路径
* @return 拷贝是否成功
*/
public static boolean copyAssetsFileToDir(Context context, String assetsFilePath, String targetFilePath) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = context.getAssets().open(assetsFilePath);
File targetFile = new File(targetFilePath);
// 覆盖已存在的文件
if (targetFile.exists() && !targetFile.delete()) {
Log.w(TAG, "覆盖目标文件失败,跳过:" + targetFilePath);
return true;
}
outputStream = new FileOutputStream(targetFile);
byte[] buffer = new byte[BUFFER_SIZE];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
Log.d(TAG, "文件拷贝成功:" + assetsFilePath + " -> " + targetFilePath);
return true;
} catch (IOException e) {
Log.e(TAG, "拷贝文件失败:" + assetsFilePath + ",异常:" + e.getMessage());
return false;
} finally {
// 关闭流
try {
if (inputStream != null) inputStream.close();
if (outputStream != null) outputStream.close();
} catch (IOException e) {
Log.e(TAG, "关闭流异常:" + e.getMessage());
}
}
}
}

View File

@@ -246,39 +246,69 @@ public class BackgroundSourceUtils {
return contentUri; return contentUri;
} }
boolean checkEmptyBackgroundAndCreateBlankBackgroundBean(BackgroundBean checkBackgroundBean) {
File fCheckBackgroundFile = new File(checkBackgroundBean.getBackgroundFilePath());
if (!fCheckBackgroundFile.exists()) {
String newCropFileName = "blank10x10";
String fileSuffix = "png";
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
AssetsCopyUtils.copyAssetsFileToDir(mContext, "images/blank10x10.png", mCropSourceFile.getAbsolutePath());
try {
mCropResultFile.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
// 加载图片数据模型数据
loadSettings();
// 修改预览数据模型
previewBackgroundBean.setIsUseBackgroundFile(true);
previewBackgroundBean.setIsUseBackgroundScaledCompressFile(false);
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
previewBackgroundBean.setBackgroundFilePath(mCropSourceFile.getAbsolutePath());
previewBackgroundBean.setBackgroundScaledCompressFileName(mCropResultFile.getName());
previewBackgroundBean.setBackgroundScaledCompressFilePath(mCropResultFile.getAbsolutePath());
// 保存数据模型数据更改
saveSettings();
return true;
}
return false;
}
/* /*
* 创建预览数据剪裁环境 * 创建预览数据剪裁环境
*/ */
public boolean createAndUpdatePreviewEnvironmentForCropping(boolean isCreateNewPreviewBean, BackgroundBean previewBackgroundBean) { public boolean createAndUpdatePreviewEnvironmentForCropping(BackgroundBean oldPreviewBackgroundBean) {
InputStream is = null; InputStream is = null;
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
clearCropTempFiles(); clearCropTempFiles();
if(checkEmptyBackgroundAndCreateBlankBackgroundBean(oldPreviewBackgroundBean)) {
return true;
}
Uri uri = UriUtil.getUriForFile(mContext, oldPreviewBackgroundBean.getBackgroundFilePath());
//String szType = mContext.getContentResolver().getType(uri);
// 2. 截取MIME类型后缀如从image/jpeg中提取jpeg【核心新增逻辑】
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
String newCropFileName = UUID.randomUUID().toString() + System.currentTimeMillis(); String newCropFileName = UUID.randomUUID().toString() + System.currentTimeMillis();
String fileSuffix;
if (isCreateNewPreviewBean) {
fileSuffix = "png";
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
DrawableToFileUtils.saveDrawableToFile(mContext, R.drawable.blank10x10, mCropSourceFile.getAbsolutePath());
mCropResultFile.createNewFile();
} else {
if (FileUtils.isFileExists(previewBackgroundBean.getBackgroundFilePath())) {
File fSourceFileOld = new File(previewBackgroundBean.getBackgroundFilePath());
Uri uri = UriUtil.getUriForFile(mContext, fSourceFileOld);
fileSuffix = FileUtils.getFileSuffix(mContext, uri);
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix); mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix); mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
FileUtils.copyFile(new File(previewBackgroundBean.getBackgroundFilePath()), mCropSourceFile); if (FileUtils.isFileExists(oldPreviewBackgroundBean.getBackgroundScaledCompressFilePath())) {
if (FileUtils.isFileExists(previewBackgroundBean.getBackgroundScaledCompressFilePath())) { FileUtils.copyFile(new File(oldPreviewBackgroundBean.getBackgroundScaledCompressFilePath()), mCropResultFile);
FileUtils.copyFile(new File(previewBackgroundBean.getBackgroundScaledCompressFilePath()), mCropResultFile);
} else { } else {
mCropResultFile.createNewFile(); mCropResultFile.createNewFile();
} }
if (FileUtils.isFileExists(oldPreviewBackgroundBean.getBackgroundFilePath())) {
FileUtils.copyFile(new File(oldPreviewBackgroundBean.getBackgroundFilePath()), mCropSourceFile);
} else {
mCropSourceFile.createNewFile(); mCropSourceFile.createNewFile();
// 1. 打开Uri输入流兼容content:///file:// 等多种Uri格式 // 1. 打开Uri输入流兼容content:///file:// 等多种Uri格式
is = mContext.getContentResolver().openInputStream(uri); is = mContext.getContentResolver().openInputStream(uri);
@@ -307,14 +337,6 @@ public class BackgroundSourceUtils {
fos.flush(); fos.flush();
} }
} }
// 解析成功日志(打印文件信息,便于问题排查)
LogUtils.d(TAG, "【选图解析】Uri解析成功");
LogUtils.d(TAG, "→ 原Uri" + uri.toString());
} else {
return createAndUpdatePreviewEnvironmentForCropping(true, previewBackgroundBean);
}
} }
// 加载图片数据模型数据 // 加载图片数据模型数据
@@ -328,12 +350,13 @@ public class BackgroundSourceUtils {
// 保存数据模型数据更改 // 保存数据模型数据更改
saveSettings(); saveSettings();
// 解析成功日志(打印文件信息,便于问题排查) // 6. 解析成功日志(打印文件信息,便于问题排查)
LogUtils.d(TAG, "【选图解析】Uri解析成功");
LogUtils.d(TAG, "→ 原Uri" + uri.toString());
LogUtils.d(TAG, "→ 图片剪裁数据源:" + mCropSourceFile.getAbsolutePath()); LogUtils.d(TAG, "→ 图片剪裁数据源:" + mCropSourceFile.getAbsolutePath());
LogUtils.d(TAG, "→ 图片剪裁数据源文件大小:" + mCropSourceFile.length() + " bytes"); LogUtils.d(TAG, "→ 图片剪裁数据源文件大小:" + mCropSourceFile.length() + " bytes");
LogUtils.d(TAG, "→ 剪裁结果数据文件:" + mCropResultFile.getAbsolutePath()); LogUtils.d(TAG, "→ 剪裁结果数据文件:" + mCropResultFile.getAbsolutePath());
LogUtils.d(TAG, "→ 剪裁结果数据文件大小:" + mCropResultFile.length() + " bytes"); LogUtils.d(TAG, "→ 剪裁结果数据文件大小:" + mCropResultFile.length() + " bytes");
return true; return true;
} catch (Exception e) { } catch (Exception e) {
@@ -477,6 +500,10 @@ public class BackgroundSourceUtils {
return fBackgroundCompressDir.getAbsolutePath(); return fBackgroundCompressDir.getAbsolutePath();
} }
public String getCropCacheDir() {
return fCropCacheDir.getAbsolutePath();
}
public String getFileProviderAuthority() { public String getFileProviderAuthority() {
return FILE_PROVIDER_AUTHORITY; return FILE_PROVIDER_AUTHORITY;
} }

View File

@@ -18,7 +18,7 @@ import cc.winboll.studio.libappbase.LogUtils;
* 特点1. 单例模式 2. 压缩加载避免OOM 3. 路径- Bitmap 映射 4. 线程安全 * 特点1. 单例模式 2. 压缩加载避免OOM 3. 路径- Bitmap 映射 4. 线程安全
*/ */
public class BitmapCacheUtils { public class BitmapCacheUtils {
private static final String TAG = "BitmapCacheUtils"; public static final String TAG = "BitmapCacheUtils";
// 最大图片尺寸适配1080P屏幕可根据需求调整 // 最大图片尺寸适配1080P屏幕可根据需求调整
private static final int MAX_WIDTH = 1080; private static final int MAX_WIDTH = 1080;
private static final int MAX_HEIGHT = 1920; private static final int MAX_HEIGHT = 1920;