- 将 Bitmap 转换为可传输的数据格式:Bitmap 本身是一个内存对象,不能直接通过网络传输,最常见的方式是将其转换为 JPEG 或 PNG 格式的字节数组(
byte[])。 - 构建 HTTP 请求:使用网络请求库(如 OkHttp、Volley 或 Retrofit)构建一个包含图片数据的 POST 请求。
- 发送请求并处理响应:将请求发送到服务器,并处理服务器返回的成功或失败信息。
下面我将为你提供一个完整、详细的指南,包含代码示例、最佳实践和注意事项。

核心步骤详解
步骤 1:将 Bitmap 转换为字节数组
在 Android 中,Bitmap 类提供了 compress() 方法,可以将位图压缩为指定的格式,并输出到一个 ByteArrayOutputStream 中。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.ByteArrayOutputStream;
public class BitmapUtils {
/**
* 将 Bitmap 转换为 JPEG 格式的字节数组
* @param bitmap 要转换的 Bitmap 对象
* @param quality 压缩质量 (0-100), 100 表示最高质量
* @return 转换后的字节数组
*/
public static byte[] bitmapToJpegByteArray(Bitmap bitmap, int quality) {
if (bitmap == null) {
return new byte[0];
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// 将 bitmap 压缩为 jpeg 格式,质量为 quality,并写入 stream
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
return stream.toByteArray();
}
/**
* 将 Bitmap 转换为 PNG 格式的字节数组
* @param bitmap 要转换的 Bitmap 对象
* @return 转换后的字节数组
*/
public static byte[] bitmapToPngByteArray(Bitmap bitmap) {
if (bitmap == null) {
return new byte[0];
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// PNG 是无损压缩,不需要质量参数
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
return stream.toByteArray();
}
}
选择 JPEG 还是 PNG?
- JPEG: 有损压缩,文件体积小,适合照片类图片,可以通过调整
quality参数来平衡图片质量和文件大小。 - PNG: 无损压缩,文件体积相对较大,但能保留所有细节,适合需要透明背景或线条图的图片。
步骤 2:使用 OkHttp 上传(推荐)
OkHttp 是目前 Android 开发中最流行、最强大的网络请求库,下面我们使用它来实现文件上传。
在 app/build.gradle 文件中添加 OkHttp 依赖:

dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0") // 使用最新版本
}
代码实现:
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class ImageUploadUtil {
private static final String TAG = "ImageUploadUtil";
private static final String UPLOAD_URL = "https://your-server.com/api/upload"; // 替换为你的服务器地址
// 创建一个 OkHttp 客户端
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
.writeTimeout(30, TimeUnit.SECONDS) // 写入超时
.readTimeout(30, TimeUnit.SECONDS) // 读取超时
.build();
/**
* 上传 Bitmap 到服务器
* @param bitmap 要上传的 Bitmap
* @param fileName 服务器上保存的文件名 ( "profile.jpg")
* @param quality JPEG 压缩质量 (0-100)
* @param callback 上传结果回调
*/
public static void uploadBitmap(Bitmap bitmap, String fileName, int quality, UploadCallback callback) {
// 1. 将 Bitmap 转换为字节数组
byte[] imageBytes = BitmapUtils.bitmapToJpegByteArray(bitmap, quality);
// 2. 创建 RequestBody
// MediaType 指定上传内容类型
RequestBody requestBody = RequestBody.create(imageBytes, MediaType.parse("image/jpeg"));
// 3. 构建 MultipartBody
// MultipartBody 用于构建包含多个部分的请求体,非常适合文件上传
MultipartBody.Part body = MultipartBody.Part.createFormData(
"image", // 服务器端接收文件时使用的参数名
fileName,
requestBody
);
// 4. 创建请求
Request request = new Request.Builder()
.url(UPLOAD_URL)
.post(MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(body)
// 你可以在这里添加其他表单字段
// .addFormDataPart("userId", "12345")
.build())
.build();
// 5. 发起异步请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 请求失败,在主线程回调
Log.e(TAG, "Upload failed: " + e.getMessage());
runOnMainThread(() -> callback.onFailure(e));
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 请求成功,读取响应
if (response.isSuccessful()) {
String responseData = response.body().string();
Log.d(TAG, "Upload successful: " + responseData);
// 在主线程回调
runOnMainThread(() -> callback.onSuccess(responseData));
} else {
// 服务器返回错误状态码 (如 400, 404, 500)
String errorResponse = response.body().string();
Log.e(TAG, "Upload failed with code " + response.code() + ": " + errorResponse);
runOnMainThread(() -> callback.onFailure(new Exception("Server error: " + response.code())));
}
}
});
}
// 辅助方法,确保回调在主线程执行
private static void runOnMainThread(Runnable runnable) {
new Handler(Looper.getMainLooper()).post(runnable);
}
// 上传回调接口
public interface UploadCallback {
void onSuccess(String response);
void onFailure(Throwable e);
}
}
步骤 3:在 Activity/Fragment 中调用
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
private Button uploadButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
uploadButton = findViewById(R.id.uploadButton);
// 加载一张示例图片
Bitmap sampleBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample_image);
imageView.setImageBitmap(sampleBitmap);
uploadButton.setOnClickListener(v -> {
// 获取 Bitmap 并开始上传
Bitmap bitmapToUpload = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
uploadImage(bitmapToUpload);
});
}
private void uploadImage(Bitmap bitmap) {
// 禁用按钮,防止重复点击
uploadButton.setEnabled(false);
ImageUploadUtil.uploadBitmap(bitmap, "my_profile.jpg", 80, new ImageUploadUtil.UploadCallback() {
@Override
public void onSuccess(String response) {
// 上传成功
Log.d("MainActivity", "Server Response: " + response);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "上传成功!", Toast.LENGTH_SHORT).show();
uploadButton.setEnabled(true);
});
}
@Override
public void onFailure(Throwable e) {
// 上传失败
Log.e("MainActivity", "Upload Error", e);
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "上传失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
uploadButton.setEnabled(true);
});
}
});
}
}
重要注意事项与最佳实践
权限声明
如果你的应用需要从存储中读取图片(从相册选择),别忘了在 AndroidManifest.xml 中声明权限:
<!-- 如果需要从相册选择 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13 (API 33) 及以上需要 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- 如果需要拍照 --> <uses-permission android:name="android.permission.CAMERA" /> <!-- 网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> ``

