上一篇
安卓开发批量上传数据
- 行业动态
- 2025-04-21
- 5
批量上传数据的核心思路
在安卓开发中,批量上传数据通常需要解决以下问题:
- 数据分批次处理:避免单次请求数据量过大导致超时或内存溢出。
- 异步任务管理:防止阻塞主线程,保证用户体验。
- 失败重试机制:应对网络波动或服务器异常。
- 进度反馈:提供上传进度提示,增强用户感知。
- 数据持久化:确保网络中断后数据不会丢失。
实现方案与代码示例
数据分批与异步上传(基于Retrofit+RxJava)
// 依赖引入(build.gradle) implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'io.reactivex.rxjava3:rxjava:3.1.8' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
// 定义API接口 public interface ApiService { @POST("upload") Single<ResponseBody> uploadData(@Body List<Data> dataList); } // 批量上传逻辑 public void batchUpload(List<Data> dataList) { int batchSize = 50; // 每批50条数据 List<Single<ResponseBody>> tasks = new ArrayList<>(); for (int i = 0; i < dataList.size(); i += batchSize) { int start = i; int end = Math.min(i + batchSize, dataList.size()); List<Data> batch = dataList.subList(start, end); tasks.add(apiService.uploadData(batch) .subscribeOn(Schedulers.io()) .retry(3) // 失败重试3次 .onErrorReturn(new Function<Throwable, ResponseBody>() { @Override public ResponseBody apply(Throwable throwable) { // 记录失败批次到本地数据库 saveFailedBatch(batch); return null; } })); } // 合并所有任务 Single.concat(tasks) .subscribe(response -> { // 全部完成后删除本地记录 deleteLocalRecords(); }, throwable -> { // 全局错误处理 showError("批量上传失败"); }); }
本地数据持久化(Room数据库)
-Entity定义 @Entity public class UploadData { @PrimaryKey(autoGenerate = true) public int id; public String jsonData; public int retryCount; }
// 失败重试机制 private void retryFailedUploads() { List<UploadData> failedData = database.uploadDao().getFailedData(); for (UploadData data : failedData) { if (data.retryCount < 3) { apiService.uploadData(parseJson(data.jsonData)) .subscribe(response -> { database.uploadDao().delete(data); }, throwable -> { data.retryCount++; database.uploadDao().update(data); }); } } }
关键优化策略
优化方向 | 实现方案 |
---|---|
性能优化 | 使用RxJava的flatMap 并发上传多个批次,控制最大并行数(如3个) |
流量压缩 | 启用Gzip压缩(Retrofit默认支持),或手动对JSON进行压缩 |
电池优化 | 使用WorkManager 替代AsyncTask ,适配后台执行限制(Android 13+) |
冲突处理 | 为每条数据生成唯一ID,服务器返回冲突时自动覆盖或保留原数据 |
常见问题与解答
问题1:如何监控上传进度并实时显示?
解答:
使用PublishSubject
传递进度事件,在上传过程中动态更新:
PublishSubject<Integer> progressSubject = PublishSubject.create(); Single.fromCallable(() -> { for (int i = 0; i < totalBatches; i++) { uploadBatch(i); // 上传第i批 progressSubject.onNext(i 100 / totalBatches); // 推送进度 } return true; }) .subscribeOn(Schedulers.io()) .subscribe(); // 订阅进度 progressSubject.subscribe(progress -> { progressBar.setProgress(progress); });
问题2:如何处理超大文件(如视频)的批量上传?
解答:
- 文件切片:将大文件分割为多个小片段(如1MB/片),逐片上传。
- 断点续传:记录已上传的片段索引,网络恢复后从断点继续。
- 服务器支持:需后端接口提供分片合并功能。
// 文件分片示例 File file = new File("video.mp4"); int chunkSize = 1024 1024; // 1MB byte[] buffer = new byte[chunkSize];
try (FileInputStream fis = new FileInputStream(file)) {
int chunkIndex = 0;
while (fis.read(buffer) != -1) {
// 上传当前分片
uploadChunk(buffer, chunkIndex);
chunkIndex++;
}
} catch (IOException e) {
e.printStackTrace();
}