使用AsyncTask压缩图片后上传至Firebase Storage的实现问询
嘿,我来帮你完善并解析这个用于Firebase Storage上传前的图片压缩AsyncTask类,直接上干货👇
完整的图片压缩AsyncTask实现
先补全你提供的截断代码,实现完整的压缩逻辑和后续上传回调:
import android.content.Context; import android.graphics.Bitmap; import android.os.AsyncTask; import android.widget.Toast; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import java.io.ByteArrayOutputStream; public class BackgroundImageResize extends AsyncTask<Void, Integer, byte[]> { private Bitmap mBitmap; private Context mContext; private OnCompressCompleteListener mListener; // 回调接口,解耦压缩完成后的逻辑 public interface OnCompressCompleteListener { void onCompressSuccess(byte[] compressedBytes); void onCompressFailed(Exception e); } public BackgroundImageResize(Context context, Bitmap bitmap, OnCompressCompleteListener listener) { this.mContext = context; if (bitmap != null) { this.mBitmap = bitmap; } this.mListener = listener; } @Override protected void onPreExecute() { super.onPreExecute(); Toast.makeText(mContext, "Compressing image...", Toast.LENGTH_SHORT).show(); // 这里可以调用你的showProgressBar()显示压缩进度 } @Override protected byte[] doInBackground(Void... voids) { if (mBitmap == null) return null; // 自定义压缩参数:质量+尺寸双重压缩 int compressQuality = 70; // 0-100,数值越小压缩率越高 int targetMaxWidth = 1024; // 图片最大宽度,超过则缩放 int targetMaxHeight = 1024; // 图片最大高度 // 先缩放图片(避免超大图直接压缩导致内存溢出) Bitmap resizedBitmap = getResizedBitmap(mBitmap, targetMaxWidth, targetMaxHeight); // 将缩放后的Bitmap转为字节数组 ByteArrayOutputStream baos = new ByteArrayOutputStream(); resizedBitmap.compress(Bitmap.CompressFormat.JPEG, compressQuality, baos); return baos.toByteArray(); } @Override protected void onPostExecute(byte[] compressedBytes) { super.onPostExecute(compressedBytes); // 这里可以调用hideProgressBar()隐藏进度条 if (compressedBytes != null && mListener != null) { mListener.onCompressSuccess(compressedBytes); // 也可以直接在这里完成Firebase上传,示例如下: uploadToFirebase(compressedBytes); } else { if (mListener != null) { mListener.onCompressFailed(new Exception("Bitmap is null or compression failed")); } Toast.makeText(mContext, "Compression failed", Toast.LENGTH_SHORT).show(); } } // 图片缩放工具方法 private Bitmap getResizedBitmap(Bitmap bitmap, int maxWidth, int maxHeight) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); // 计算缩放比例,取宽高中最小的缩放值保证图片不拉伸 float scaleRatio = Math.min((float) maxWidth / width, (float) maxHeight / height); // 原图尺寸小于目标尺寸,直接返回原Bitmap if (scaleRatio >= 1.0f) return bitmap; // 创建缩放后的Bitmap return Bitmap.createScaledBitmap(bitmap, (int) (width * scaleRatio), (int) (height * scaleRatio), true); } // 上传到Firebase Storage的示例方法 private void uploadToFirebase(byte[] compressedBytes) { StorageReference storageRef = FirebaseStorage.getInstance().getReference(); // 用时间戳作为文件名避免重复 StorageReference imageRef = storageRef.child("uploaded_images/" + System.currentTimeMillis() + ".jpg"); UploadTask uploadTask = imageRef.putBytes(compressedBytes); uploadTask.addOnSuccessListener(taskSnapshot -> { Toast.makeText(mContext, "Image uploaded successfully!", Toast.LENGTH_SHORT).show(); // 可以获取图片下载URL imageRef.getDownloadUrl().addOnSuccessListener(uri -> { String downloadUrl = uri.toString(); // 这里可以把URL保存到Firestore或本地 }); }).addOnFailureListener(e -> { Toast.makeText(mContext, "Upload failed: " + e.getMessage(), Toast.LENGTH_SHORT).show(); }); } }
关键细节解析
- 避免内存泄漏:把原来硬编码的
NextActivity.this改成传入Context+回调接口,防止AsyncTask持有Activity强引用导致内存泄漏。 - 双重压缩策略:先缩放超大图再按质量压缩,既保证压缩效果,又避免直接压缩大图引发OOM。
- 解耦设计:通过
OnCompressCompleteListener接口,让压缩后的逻辑(比如上传、本地保存)可以灵活自定义,不局限于固定流程。
Activity中使用示例
// 假设你已经通过拍照/相册获取到了原始Bitmap Bitmap originalBitmap = ...; new BackgroundImageResize(this, originalBitmap, new BackgroundImageResize.OnCompressCompleteListener() { @Override public void onCompressSuccess(byte[] compressedBytes) { // 自定义处理压缩后的字节数组,比如自己实现上传逻辑 } @Override public void onCompressFailed(Exception e) { // 处理压缩失败的情况,比如提示用户重新选择图片 } }).execute();
额外提醒
从Android API 30开始,AsyncTask已被官方标记为废弃,如果是新项目,建议改用Coroutines + Dispatcher.IO或者ExecutorService实现后台任务,兼容性和可控性更好。另外,压缩完成后记得回收不再使用的Bitmap:originalBitmap.recycle();,避免内存浪费。
内容的提问来源于stack exchange,提问作者Aditya Sissodiya
相关产品推荐
相关产品推荐

