改进网络图片下载与预览

This commit is contained in:
ZhanGSKen
2025-11-21 03:38:42 +08:00
parent 47ea47cddc
commit 81950699b3
2 changed files with 131 additions and 57 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Fri Nov 21 03:21:01 HKT 2025 #Thu Nov 20 19:36:49 GMT 2025
stageCount=5 stageCount=5
libraryProject= libraryProject=
baseVersion=15.11 baseVersion=15.11
publishVersion=15.11.4 publishVersion=15.11.4
buildCount=0 buildCount=2
baseBetaVersion=15.11.5 baseBetaVersion=15.11.5

View File

@@ -2,11 +2,12 @@ package cc.winboll.studio.powerbell.dialogs;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
@@ -14,9 +15,11 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.utils.ImageDownloader; import cc.winboll.studio.powerbell.utils.ImageDownloader;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
import android.content.DialogInterface;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
@@ -25,17 +28,23 @@ import cc.winboll.studio.powerbell.views.BackgroundView;
* 继承 AndroidX AlertDialog绑定自定义布局 dialog_networkbackground.xml * 继承 AndroidX AlertDialog绑定自定义布局 dialog_networkbackground.xml
*/ */
public class NetworkBackgroundDialog extends AlertDialog { public class NetworkBackgroundDialog extends AlertDialog {
public static final String TAG = "NetworkBackgroundDialog"; public static final String TAG = "NetworkBackgroundDialog";
// 消息标识:图片加载成功
private static final int MSG_IMAGE_LOAD_SUCCESS = 1001;
// 消息标识:图片加载失败
private static final int MSG_IMAGE_LOAD_FAILED = 1002;
// 控件引用 // 控件引用
private TextView tvTitle; private TextView tvTitle;
private TextView tvContent; private TextView tvContent;
private Button btnCancel; private Button btnCancel;
private Button btnConfirm; private Button btnConfirm;
private Button btnPreview; private Button btnPreview;
private EditText etURL; private EditText etURL;
BackgroundView bvBackgroundPreview; BackgroundView bvBackgroundPreview;
Context mContext; Context mContext;
// 主线程 Handler用于接收子线程消息并更新 UI
private Handler mUiHandler;
// 按钮点击回调接口Java7 接口实现) // 按钮点击回调接口Java7 接口实现)
public interface OnDialogClickListener { public interface OnDialogClickListener {
@@ -48,21 +57,69 @@ public class NetworkBackgroundDialog extends AlertDialog {
// Java7 显式构造(必须传入 Context // Java7 显式构造(必须传入 Context
public NetworkBackgroundDialog(@NonNull Context context) { public NetworkBackgroundDialog(@NonNull Context context) {
super(context); super(context);
initHandler(); // 初始化 Handler
initView(); // 初始化布局和控件 initView(); // 初始化布局和控件
setDismissListener(); // 设置对话框消失监听
} }
// 带回调的构造(便于外部处理点击事件) // 带回调的构造(便于外部处理点击事件)
public NetworkBackgroundDialog(@NonNull Context context, OnDialogClickListener listener) { public NetworkBackgroundDialog(@NonNull Context context, OnDialogClickListener listener) {
super(context); super(context);
this.listener = listener; this.listener = listener;
initHandler(); // 初始化 Handler
initView(); initView();
setDismissListener(); // 设置对话框消失监听
}
/**
* 初始化主线程 Handler用于更新 UI
*/
private void initHandler() {
mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 对话框已消失时,不再处理 UI 消息
if (!isShowing()) {
return;
}
switch (msg.what) {
case MSG_IMAGE_LOAD_SUCCESS:
// 图片加载成功,获取文件路径并设置背景
String filePath = (String) msg.obj;
setBackgroundFromPath(filePath);
break;
case MSG_IMAGE_LOAD_FAILED:
// 图片加载失败,设置默认背景
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
ToastUtils.show("图片预览失败,请检查链接");
break;
}
}
};
}
/**
* 设置对话框消失监听:移除 Handler 消息,避免内存泄漏
*/
private void setDismissListener() {
this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
// 对话框消失时,移除所有未处理的消息和回调
if (mUiHandler != null) {
mUiHandler.removeCallbacksAndMessages(null);
}
LogUtils.d(TAG, "对话框已消失Handler 消息已清理");
}
});
} }
/** /**
* 初始化布局和控件 * 初始化布局和控件
*/ */
private void initView() { private void initView() {
mContext = this.getContext(); mContext = this.getContext();
// 加载自定义布局 // 加载自定义布局
View dialogView = LayoutInflater.from(getContext()) View dialogView = LayoutInflater.from(getContext())
.inflate(R.layout.dialog_networkbackground, null); .inflate(R.layout.dialog_networkbackground, null);
@@ -74,10 +131,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
tvContent = (TextView) dialogView.findViewById(R.id.tv_dialog_content); tvContent = (TextView) dialogView.findViewById(R.id.tv_dialog_content);
btnCancel = (Button) dialogView.findViewById(R.id.btn_cancel); btnCancel = (Button) dialogView.findViewById(R.id.btn_cancel);
btnConfirm = (Button) dialogView.findViewById(R.id.btn_confirm); btnConfirm = (Button) dialogView.findViewById(R.id.btn_confirm);
btnPreview = (Button) dialogView.findViewById(R.id.btn_preview); btnPreview = (Button) dialogView.findViewById(R.id.btn_preview);
etURL = (EditText) dialogView.findViewById(R.id.et_url); etURL = (EditText) dialogView.findViewById(R.id.et_url);
//webViewPreview = (WebView) dialogView.findViewById(R.id.webview_preview); bvBackgroundPreview = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview);
bvBackgroundPreview = (BackgroundView) findViewById(R.id.bv_background_preview);
// 设置按钮点击事件 // 设置按钮点击事件
setButtonClickListeners(); setButtonClickListeners();
@@ -116,12 +172,56 @@ public class NetworkBackgroundDialog extends AlertDialog {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认预览点击"); LogUtils.d("NetworkBackgroundDialog", "确认预览点击");
String url = etURL.getText().toString(); String url = etURL.getText().toString().trim();
if (url.isEmpty()) {
ToastUtils.show("请输入图片链接");
return;
}
ImageDownloader.getInstance(mContext).downloadImage(url, mDownloadCallback); ImageDownloader.getInstance(mContext).downloadImage(url, mDownloadCallback);
} }
}); });
} }
/**
* 根据文件路径设置 BackgroundView 背景(主线程调用)
* @param filePath 图片文件路径
*/
private void setBackgroundFromPath(String filePath) {
FileInputStream fis = null;
try {
File imageFile = new File(filePath);
if (!imageFile.exists()) {
LogUtils.e(TAG, "图片文件不存在:" + filePath);
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
return;
}
fis = new FileInputStream(imageFile);
Drawable drawable = Drawable.createFromStream(fis, null);
// 设置背景(主线程安全操作)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
bvBackgroundPreview.setBackground(drawable);
} else {
bvBackgroundPreview.setBackgroundDrawable(drawable);
}
LogUtils.d(TAG, "图片预览成功:" + filePath);
} catch (Exception e) {
e.printStackTrace();
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
LogUtils.e(TAG, "图片预览失败:" + e.getMessage());
} finally {
// Java7 手动关闭流,避免资源泄漏
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/** /**
* 对外提供方法:修改对话框标题(灵活适配不同场景) * 对外提供方法:修改对话框标题(灵活适配不同场景)
*/ */
@@ -147,49 +247,23 @@ public class NetworkBackgroundDialog extends AlertDialog {
this.listener = listener; this.listener = listener;
} }
ImageDownloader.DownloadCallback mDownloadCallback = new ImageDownloader.DownloadCallback(){ ImageDownloader.DownloadCallback mDownloadCallback = new ImageDownloader.DownloadCallback() {
@Override
public void onSuccess(String filePath) {
ToastUtils.show("图片下载成功:" + filePath);
LogUtils.d(TAG, filePath);
// 发送消息到主线程,携带图片路径
Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, filePath);
mUiHandler.sendMessage(successMsg);
}
@Override @Override
public void onSuccess(String filePath) { public void onFailure(String errorMsg) {
ToastUtils.show(filePath); ToastUtils.show("下载失败:" + errorMsg);
LogUtils.d(TAG, filePath); LogUtils.e(TAG, errorMsg);
// 发送图片加载失败消息
String imagePath = "/storage/emulated/0/Android/data/cc.winboll.studio.powerbell.beta/files/mmexport1713182627221.png"; mUiHandler.sendEmptyMessage(MSG_IMAGE_LOAD_FAILED);
//String imagePath = filePath; }
};
FileInputStream fis = null;
try {
fis = new FileInputStream(imagePath);
Drawable drawable = Drawable.createFromStream(fis, null);
// 设置背景
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
bvBackgroundPreview.setBackground(drawable);
} else {
bvBackgroundPreview.setBackgroundDrawable(drawable);
}
} catch (Exception e) {
e.printStackTrace();
//ivBackgroundPreview.setBackgroundResource(R.drawable.default_error); // 异常时显示默认图
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher); // 异常时显示默认图
} finally {
// Java7 手动关闭流,避免资源泄漏
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onFailure(String errorMsg) {
ToastUtils.show(errorMsg);
LogUtils.d(TAG, errorMsg);
}
};
} }