You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:41:07