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

如何压缩图片并保存至Firebase Cloud Storage?Android开发求助

Android图片压缩至100KB左右并上传Firebase解决方案

问题修正与核心思路

你的现有代码直接上传选中的原图,未做压缩处理,还存在变量误用(回调里的result才是选中图片的Uri,代码里错用了mImgUri)。下面是结合尺寸压缩+质量压缩实现目标的完整方案,既能把图片压到100KB左右,又能尽量保留画质。

完整代码实现

1. 图片压缩工具方法

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class ImageCompressor {
    // 目标压缩大小(100KB)
    private static final long TARGET_SIZE = 100 * 1024;

    /**
     * 将Uri转为压缩后的临时文件
     */
    public static File compressImage(Context context, Uri imageUri) throws IOException {
        // 1. 先获取原图尺寸,计算缩小比例
        InputStream inputStream = context.getContentResolver().openInputStream(imageUri);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(inputStream, null, options);
        inputStream.close();

        // 把大图先缩到1080P以内,避免直接压缩导致画质崩
        options.inSampleSize = calculateSampleSize(options, 1080, 1920);
        options.inJustDecodeBounds = false;
        inputStream = context.getContentResolver().openInputStream(imageUri);
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
        inputStream.close();

        // 2. 循环调整质量压缩,直到接近目标大小
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int quality = 100;
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        while (baos.toByteArray().length > TARGET_SIZE && quality > 10) {
            baos.reset();
            quality -= 10;
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        }

        // 3. 写入临时文件供上传
        File tempFile = File.createTempFile("compressed_img", ".jpg", context.getCacheDir());
        FileOutputStream fos = new FileOutputStream(tempFile);
        fos.write(baos.toByteArray());
        fos.flush();
        fos.close();
        bitmap.recycle(); // 释放Bitmap内存,防止OOM

        return tempFile;
    }

    /**
     * 计算图片缩小比例
     */
    private static int calculateSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
        int width = options.outWidth;
        int height = options.outHeight;
        int sampleSize = 1;

        if (height > maxHeight || width > maxWidth) {
            int halfHeight = height / 2;
            int halfWidth = width / 2;
            while ((halfHeight / sampleSize) >= maxHeight && (halfWidth / sampleSize) >= maxWidth) {
                sampleSize *= 2;
            }
        }
        return sampleSize;
    }
}

2. 修改后的图片选择与上传代码

// 注册图片选择启动器
ActivityResultLauncher<String> launcher = registerForActivityResult(
        new ActivityResultContracts.GetContent(),
        result -> {
            if (result == null) return;

            // 压缩是耗时操作,必须放子线程
            new Thread(() -> {
                try {
                    // 压缩图片到临时文件
                    File compressedFile = ImageCompressor.compressImage(getApplicationContext(), result);

                    // 上传压缩后的文件到Firebase
                    StorageReference reference = FirebaseStorage.getInstance()
                            .getReference("MESSAGE")
                            .child(mMsgPath)
                            .child(System.currentTimeMillis() + ".jpg"); // 用时间戳做文件名,避免重复覆盖

                    reference.putFile(Uri.fromFile(compressedFile))
                            .addOnSuccessListener(taskSnapshot -> {
                                reference.getDownloadUrl().addOnSuccessListener(uri -> {
                                    String url = uri.toString();
                                    // 这里可以把url存入聊天消息列表
                                });
                            })
                            .addOnFailureListener(e -> {
                                // 处理上传失败逻辑
                            });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        });

// 启动图片选择
launcher.launch("image/*");

新手必看注意事项

  • 压缩必须放子线程,否则会导致App卡顿甚至ANR
  • 用时间戳做文件名,避免上传时覆盖同路径下的旧图片
  • 压缩后记得调用bitmap.recycle()释放内存,防止内存溢出
  • 如果需要处理拍照后图片旋转的问题,可以在压缩工具类里补充Exif信息读取逻辑(新手可后期再优化)

内容的提问来源于stack exchange,提问作者Mukesh Roy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:24:42