android网络请求进度条:5分钟带你搞懂OkHttp断点上传
android网络请求进度条:5分钟带你搞懂OkHttp断点上传有了FileRequestBody类,我们只需要传入一个断点位置,剩下的工作就跟普通的文件上传一样。 接下来,直接进入代码实现。//为简化阅读,已省略部分代码 public class FileRequestBody extends RequestBody { private final File file; private final long skipSize; //断点位置 private final MediaType mediaType; public FileRequestBody(File file long skipSize @Nullable MediaType mediaType) { this.file = file; this.skipSize = skipSize; this
作者:刘一刀
经常会有同学问:文件的断点上传如何实现?
断点上传/下载,这是在客户端经常遇到的场景,当我们需要上传或下载一个大文件时,都会考虑使用断点续传的方式。
断点上传相较于断点下载来说,最大的区别就在于断点位置的记录,上传记录在服务端,下载记录在客户端,因此,客户端需要在上传前,通过接口去拿到文件的断点位置,然后在上传时,将文件输入流跳转到断点位置
一、准备工作对于文件上传,其实就是打开文件的输入流,不停的读取数据到byte数组中,随后写出到服务端;那客户端要做的就是跳过已经上传的部分,也就是直接跳到断点位置,这样就可以从断点位置去读取数据,也就达到了断点上传的目的。
伪代码如下:
String filePath = "...";
long skipSize = 100; //假设断点位置是 100 byte
InputStream input = input = new FileInputStream(filePath);
input.skip(skipSize) //跳转到断点位置
然而,OkHttp并没有直接提供设置断点的方法,所以需要客户端自定义RequestBody,取名为FileRequestBody,如下:
//为简化阅读,已省略部分代码
public class FileRequestBody extends RequestBody {
private final File file;
private final long skipSize; //断点位置
private final MediaType mediaType;
public FileRequestBody(File file long skipSize @Nullable MediaType mediaType) {
this.file = file;
this.skipSize = skipSize;
this.mediaType = mediaType;
}
@Override
public long contentLength() throws IOException {
return file.length() - skipSize;
}
@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
InputStream input = null;
Source source = null;
try {
input = new FileInputStream(file);
if (skipSize > 0) {
input.skip(skipSize); //跳到断点位置
}
source = Okio.source(input);
sink.writeAll(source);
} finally {
OkHttpCompat.closeQuietly(source input);
}
}
}
为方便阅读,以上省略部分源码,FileRequestBody类完整源码
有了FileRequestBody类,我们只需要传入一个断点位置,剩下的工作就跟普通的文件上传一样。 接下来,直接进入代码实现。
二、代码实现2.1 获取断点位置首先,需要服务端提供一个接口,通过userId去查找该用户未上传完成的任务列表,代码如下:
RxHttp.get("/.../getToUploadTask")
.add("userId" "88888888")
.asList<ToUploadTask>()
.subscribe({
//成功回调,这里通过 it 拿到 List<ToUploadTask>
} {
//异常回调
});
其中ToUploadTask类如下:
//待上传任务
data class ToUploadTask(
val md5: String //文件的md5,用于验证文件的唯一性
val filePath: String //文件在客户端的绝对路径
val skipSize: Long = 0 //断点位置
)
注:md5、filePath 这两个参数需要客户端在文件上传时传递给服务端,用于对文件的校验,防止文件错乱
2.2 断点上传有了待上传任务,客户端就可以执行断点上传操作,OkHttp代码如下:
fun uploadFile(uploadTask: ToUploadTask) {
//1.校验文件是否存在
val file = File(uploadTask.filePath)
if (!file.exists() && !file.isFile) return
//2.校验文件的 md5 值
val fileMd5 = FileUtils.getFileMD5ToString(file)
if (!fileMd5.equals(uploadTask.md5)) return
//3.构建请求体
val fileRequestBody = FileRequestBody(file uploadTask.skipSize BuildUtil.getMediaType(file.name))
val multipartBody = MultipartBody.Builder()
.addFormDataPart("userId" "88888888")
.addFormDataPart("md5" fileMd5)
.addFormDataPart("filePath" file.absolutePath)
.addFormDataPart("file" file.name fileRequestBody) //添加文件body
.build()
//4.构建请求
val request = Request.Builder()
.url("/.../uploadFile")
.post(multipartBody)
.build()
//5.执行请求
val okClient = OkHttpClient.Builder().build()
okClient.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call e: IOException) {
//异常回调
}
override fun onResponse(call: Call response: Response) {
//成功回调
}
})
}
FIleUtils源码,BuildUtil源码
当然,考虑到很少人会直接使用OkHttp,所以这里也贴出RxHttp的实现代码,很简单,仅需构建一个UpFile对象即可,就可很方便的监听上传进度,代码如下:
fun uploadFile(uploadTask: ToUploadTask) {
//1.校验文件是否存在
val file = File(uploadTask.filePath)
if (!file.exists() && !file.isFile) return
//2.校验文件的 md5 值
val fileMd5 = FileUtils.getFileMD5ToString(file)
if (!fileMd5.equals(uploadTask.md5)) return
val upFile = UpFile("file" file file.name uploadTask.skipSize)
//3.直接上传
RxHttp.postForm("/.../uploadFile")
.add("userId" "88888888")
.add("md5" fileMd5)
.add("filePath" file.absolutePath)
.addFile(upFile)
.upload(AndroidSchedulers.mainThread()) {
//上传进度回调
}
.asString()
.subscribe({
//成功回调
} {
//异常回调
})
}
小结
断点上传相较普通的文件上传,客户端多了一个断点的设置,大部分工作量在服务端,服务端不仅需要处理文件的拼接逻辑,还需记录未上传完成的任务,并通过接口暴露给客户端。
在这里还分享一份由大佬亲自收录整理的学习PDF 架构视频 面试文档 源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
当然,你也可以拿去查漏补缺,提升自身的竞争力。
真心希望可以帮助到大家,Android路漫漫,共勉!
如果你有需要的话,只需私信我【进阶】即可获取