当前位置:首页 > 行业动态 > 正文

安卓上传file图片到服务器

使用MultipartEntityBuilder构建请求,添加FileBody文件参数,设置Content-Type为image/jpeg,通过HttpClient执行POST请求,处理服务器响应获取上传结果,需配置网络权限及文件读取权限

权限处理

安卓系统需要动态申请存储权限(读取/写入外部存储)

权限类型 申请方式 适用场景
READ_EXTERNAL_STORAGE Manifest.permission.READ_EXTERNAL_STORAGE 读取本地图片
WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE 保存缓存图片(可选)
READ_MEDIA_IMAGES Manifest.permission.READ_MEDIA_IMAGES Android 13+ 替代方案
// 检查并请求权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE);
}

图片选择方式

通过系统相册选择

Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE);

通过文件管理器选择

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/");
startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE);

处理选中的图片

数据类型 处理方式 注意事项
Uri(Android 11+) 直接使用URI上传 不需要转换路径
Uri(Android 10-) 通过ContentResolver获取真实路径 需要处理不同厂商的URI格式
Bitmap 压缩后转为File 注意内存占用
// 获取文件路径(Android 10以下)
public String getRealPathFromURI(Uri uri) {
    String[] projection = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
    if (cursor != null) {
        cursor.moveToFirst();
        String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
        return path;
    }
    return null;
}

图片上传实现

使用OkHttp上传

OkHttpClient client = new OkHttpClient();
// 创建请求体
MultipartBody body = new MultipartBody.Builder()
    .setType(MultipartBody.FORM)
    .addFormDataPart("file", fileName, RequestBody.create(mediaType, file))
    .build();
// 创建请求
Request request = new Request.Builder()
    .url("https://yourserver.com/upload")
    .post(body)
    .build();
// 异步执行
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 处理失败
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // 处理成功
    }
});

服务器端接收示例

技术栈 关键代码 文件保存位置
Spring Boot @RequestParam MultipartFile file /uploads/目录
Flask request.files['file'] upload/目录
Express multer中间件 public/uploads/目录
// Spring Boot示例
@PostMapping("/upload")
public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile file) {
    try {
        String path = "/uploads/" + file.getOriginalFilename();
        file.transferTo(new File(path));
        return ResponseEntity.ok("上传成功");
    } catch (IOException e) {
        return ResponseEntity.status(500).body("上传失败");
    }
}

常见问题解决方案

问题现象 解决方案 代码示例
权限被拒绝 添加权限声明和动态申请 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
文件路径为空 使用ContentResolver获取InputStream InputStream is = getContentResolver().openInputStream(uri);
上传失败404 检查服务器接口地址 确保URL包含协议(http/https)
大文件上传慢 显示进度对话框 使用ProgressBar配合onResponse回调

相关问题与解答

Q1:如何压缩图片以减少上传时间?
A1:使用BitmapFactory.Options进行采样压缩:

Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, new BitmapFactory.Options());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos); // 质量压缩到80%
byte[] bytes = baos.toByteArray();

Q2:如何处理Android 11+的分区存储限制?
A2:使用Scoped Storage适配方案:

  1. 使用MediaStore.createAtomicFile()保存临时文件
  2. 通过ACTION_OPEN_DOCUMENT获取持久化访问权限
  3. 使用ContentResolver直接操作URI而非文件
0