在安卓开发中,批量上传数据通常需要解决以下问题:
// 依赖引入(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("批量上传失败"); }); }
-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,服务器返回冲突时自动覆盖或保留原数据 |
解答:
使用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); });
解答:
// 文件分片示例 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();
}