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

Android Studio如何实现文件高压缩后上传至AWS Amplify S3云存储

AWS Amplify S3 上传前文件最优压缩实现方案

核心原则:所有压缩逻辑在调用Amplify上传接口前执行,不要将原始文件流直接传入上传方法,将压缩完成后的流作为上传输入源即可,分图片、视频两类场景分别处理:

图片压缩(可稳定实现1.5MB文件压缩至120KB左右的效果)

不需要引入重型第三方库,用Android原生API就能实现目标压缩率,逻辑分两步:

  • 第一步采样压缩:解码图片前先读取原图尺寸,按比例计算采样值,只加载适配移动端观看的尺寸到内存,常规场景把图片长边限制在1280px即可,既避免加载全尺寸图导致OOM,也从根源减少文件体积
  • 第二步阶梯质量压缩:优先选WebP有损格式(压缩率比JPEG高30%左右,低版本安卓兼容JPEG),从80%质量开始逐步下调,每次压缩后判断输出字节数组大小,直到落到100KB-130KB的目标区间,最低质量不低于30%避免画质劣化过于明显
    用这套逻辑处理普通手机拍摄的1.5MB左右照片,最终输出体积基本稳定在120KB上下,肉眼几乎看不出画质差异。

视频压缩

视频不要手写编码逻辑,直接用系统自带MediaCodec做转码即可,参数按以下设置就能平衡体积和画质:

  • 分辨率:原视频分辨率高于1080p的压到1080p,普通短视频压到720p足够移动端观看
  • 码率设置为1.5Mbps-2Mbps,帧率固定25fps,编码用H.264格式保证全设备兼容
  • 压缩属于耗时计算操作,必须放在工作线程/协程中执行,压缩结果输出到应用私有目录的临时缓存文件,上传完成后及时删除临时文件避免占用存储。

改造后的可直接复用的上传代码

首先实现图片压缩工具方法:

private InputStream compressImage(Context context, Uri imageUri, long targetSizeKB) throws IOException {
    // 第一次解码仅读取原图尺寸,不加载像素到内存
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    try (InputStream boundsIn = context.getContentResolver().openInputStream(imageUri)) {
        BitmapFactory.decodeStream(boundsIn, null, options);
    }

    // 计算采样率,限制长边最大为1280px
    int maxEdge = 1280;
    int sampleSize = 1;
    if (options.outHeight > maxEdge || options.outWidth > maxEdge) {
        int heightRatio = Math.round((float) options.outHeight / (float) maxEdge);
        int widthRatio = Math.round((float) options.outWidth / (float) maxEdge);
        sampleSize = Math.min(heightRatio, widthRatio);
    }
    options.inSampleSize = sampleSize;
    options.inJustDecodeBounds = false;

    // 采样解码得到缩小后的位图
    Bitmap sampledBitmap;
    try (InputStream bitmapIn = context.getContentResolver().openInputStream(imageUri)) {
        sampledBitmap = BitmapFactory.decodeStream(bitmapIn, null, options);
    }

    // 阶梯调整压缩质量,直到达到目标体积
    ByteArrayOutputStream compressOut = new ByteArrayOutputStream();
    int quality = 80;
    // 高版本安卓用WebP格式获得更高压缩率,低版本回退JPEG
    Bitmap.CompressFormat compressFormat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ?
            Bitmap.CompressFormat.WEBP_LOSSY : Bitmap.CompressFormat.JPEG;
    sampledBitmap.compress(compressFormat, quality, compressOut);
    while (compressOut.toByteArray().length / 1024 > targetSizeKB && quality > 30) {
        compressOut.reset();
        quality -= 5;
        sampledBitmap.compress(compressFormat, quality, compressOut);
    }
    // 回收位图释放内存
    sampledBitmap.recycle();
    return new ByteArrayInputStream(compressOut.toByteArray());
}

替换原有的上传逻辑,将原始流替换为压缩后的流:

try {
    // 压缩图片,目标体积设为120KB
    InputStream compressedStream = compressImage(this, uri, 120);

    Amplify.Storage.uploadInputStream(
            editText.getText().toString(),
            compressedStream,
            StorageUploadInputStreamOptions.defaultInstance(),
            this::showProgress,
            result -> {
                // 上传完成关闭流
                try {
                    compressedStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                uploded(result);
            },
            failure -> {
                // 上传失败也要关闭流
                try {
                    compressedStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Log.e("MyAmplifyApp", "Upload failed", failure);
            }
    );
} catch (FileNotFoundException error) {
    Log.e("MyAmplifyApp", "Could not find file to open for input stream.", error);
} catch (IOException e) {
    Log.e("MyAmplifyApp", "File compress failed", e);
}

落地注意事项:

  • 所有压缩、解码操作禁止在主线程执行,否则会触发ANR
  • 批量上传场景可以将压缩+上传逻辑放到前台服务中执行,避免应用退后台后进程被系统杀掉中断任务
  • 优先在客户端完成压缩,相比服务端压缩的方案,能大幅减少上传流量消耗、缩短上传等待时间,整体成本更低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:18:23