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

安卓发送文件到服务器端

安卓发送文件至服务器需配置网络权限,使用OkHttp或Retrofit库构建Multipart请求,读取文件流并上传,需异步处理(如协程)避免阻塞, 服务器端需提供接收接口,注意文件路径权限及网络异常处理

安卓发送文件到服务器端实现指南


权限配置

  1. AndroidManifest.xml 中声明存储权限:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  2. 动态申请权限(Android 6.0+):
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE);
    }

网络请求构建

  1. 使用 OkHttp 发送文件

    File file = new File(filePath); // 本地文件路径
    OkHttpClient client = new OkHttpClient();
    RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.getName(), RequestBody.create(file, MediaType.parse("application/octet-stream")))
        .build();
    Request request = new Request.Builder()
        .url("https://your-server.com/upload") // 服务器上传接口
        .post(requestBody)
        .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 { / 处理成功 / }
    });
  2. 使用 Retrofit 发送文件

    // 定义接口
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadFile(@Part MultipartBody.Part file);
    // 调用接口
    File file = new File(filePath);
    RequestBody requestBody = RequestBody.create(file, MediaType.parse("application/octet-stream"));
    MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
    retrofit.create(ApiService.class).uploadFile(part).enqueue(new Callback<>() {
        @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { / 成功逻辑 / }
        @Override public void onFailure(Call<ResponseBody> call, Throwable t) { / 失败逻辑 / }
    });

异步处理与进度显示

  1. 进度监听(OkHttp)

    // 自定义 RequestBody 统计上传进度
    CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.Listener() {
        @Override public void onRequestProgress(long bytesWritten, long contentLength) {
            float progress = (float) bytesWritten / contentLength  100;
            // 更新 UI(需切换到主线程)
        }
    });
  2. 结合 RxJava/Coroutines

    • RxJava:通过 io()mainThread() 切换线程。
    • Kotlin Coroutines:使用 withContext(Dispatchers.IO) 处理网络请求。

服务器端处理(示例:Spring Boot)

@RestController
public class FileController {
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            String path = "server/path/" + file.getOriginalFilename();
            file.transferTo(new File(path)); // 保存文件
            return ResponseEntity.ok("Success");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("Error: " + e.getMessage());
        }
    }
}

单元表格:关键步骤与代码片段

步骤 代码/配置
权限声明 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
动态权限申请 ActivityCompat.requestPermissions()
构建 Multipart 请求体 MultipartBody.Builder().addFormDataPart()
异步执行网络请求 enqueue(new Callback())withContext(Dispatchers.IO)
进度监听 自定义 CountingRequestBody 或拦截器统计字节数
服务器端接收文件 @RequestParam MultipartFile + transferTo()

相关问题与解答

问题1:如何支持多文件同时上传?

解答
在客户端构建多个 MultipartBody.Part

MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
for (File file : fileList) {
    builder.addFormDataPart("files[]", file.getName(), RequestBody.create(file, MediaType.parse("application/octet-stream")));
}

服务器端需解析数组形式的文件参数(如 files[])。


问题2:如何处理大文件的分片上传?

解答

  1. 客户端分片:将文件分割为固定大小(如 1MB/片),逐片上传。
  2. 服务器合并:每片上传后暂存,全部完成后合并为完整文件。
  3. 断点续传:记录已上传的片索引,失败时从中断处继续。

示例(分片逻辑)

int chunkSize = 1024  1024; // 1MB
for (int i = 0; i < file.length(); i += chunkSize) {
    byte[] chunk = Arrays.copyOfRange(fileBytes, i, Math.min(i + chunkSize, file.length()));
    // 上传 chunk 并记录进度
}