本文简单写一下自己用到的OkHttp表单提交文件监听回调
本文用kotlin实现
首先有这样一个问题,文件上传进度哪里来? 因为我们是将文件上传到服务器,我们可以把文件解读成一个字节一个字节的上传,这样,我们读取文件的进度就是文件上传的进度。
1.首先我们一个类继承RequestBody,不过要重写几个方法
/**
* requestBody 请求体
* 文件上传进度回调
*/
class ProgressBody(var requestBody: RequestBody) : RequestBody() {
//用于监听文件的上传进度回调
private lateinit var callBack: (Long, Long) -> Unit
private var mCurrentLength: Long = 0
constructor(requestBody: RequestBody, callBack: (Long, Long) -> Unit) : this(requestBody) {
this.callBack = callBack
}
/**
* 请求体的contentType
*/
override fun contentType(): MediaType {
return requestBody.contentType()!!
}
/**
* 文件写入
*/
override fun writeTo(sink: BufferedSink?) {
//获取总长度
val contentLength = contentLength()
val forwardingSink = object : ForwardingSink(sink) {
override fun write(source: Buffer, byteCount: Long) {
//增加当前写入的字节数
mCurrentLength += byteCount
if (callBack != null) {
//返回当前进度
callBack(mCurrentLength, contentLength)
}
super.write(source, byteCount)
}
}
val buffer = Okio.buffer(forwardingSink)
requestBody.writeTo(buffer)
// 刷新
buffer.flush()
}
/**
* 获取请求体总长度
*/
override fun contentLength(): Long {
return requestBody.contentLength()
}
}
2.我们简单获取一个OkHttp的实例
class UploadManager constructor(){
private var okHttpClient: OkHttpClient
init{
okHttpClient = OkHttpClient.Builder()
.connectTimeout(50, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.followRedirects(true)
.addInterceptor(CommonTokenInterceptor().baseURLInterceptor())
.retryOnConnectionFailure(true)
.build()
}
}
3.我们是上传文件到Oss,所以简单一下表单上传需要的参数
/**
* 单个上传文件
* @param policy 上传策略返回
* @param index 文件索引
* @param file 文件
* @param progress 上传进度回调
* @param complete 上传完成回调
*/
override fun uploadFileToOss(policy: FormDataPolicy, index: Int,
file: File, progress: (String) -> Unit, @NotNull complete: (FileEntity?) -> Unit,
uploadFail: (String?) -> Unit) {
val policyResult = policy?.files?.get(index)
?: return
if (TextUtils.isEmpty(policyResult?.key)) {
complete(policyResult?.file)
return
}
val fileBody = RequestBody.create(MediaType.parse(getMimeType(file.absolutePath)), file)
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("OSSAccessKeyId", policy?.accessId)
.addFormDataPart("Signature", policyResult?.signature)
.addFormDataPart("callback", policy?.callback)
.addFormDataPart("key", policyResult?.key)
.addFormDataPart("policy", policyResult?.policy)
.addFormDataPart("success_action_status", "200")
.addFormDataPart("x-oss-forbid-overwrite", "true")
.addFormDataPart("file", file.name, fileBody)
.build()
//回调监听
val progressBody = ProgressBody(requestBody) { currentLength, ContentLength ->
progress(((currentLength.toFloat() / ContentLength.toFloat()) * 100).toInt().toString())
}
val request = Request.Builder().post(progressBody).url(policy?.host).build()
val call: Call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call?, e: IOException?) {
uploadFail(e?.message)
}
override fun onResponse(call: Call?, response: okhttp3.Response?) {
if (response?.isSuccessful!!) {
val string = response.body().string()
val type = object : TypeToken<FileEntity>() {}.type
val file = gson.fromJson<FileEntity>(string, type)
complete(file)
} else {
complete(null)
}
}
})
}
这里有部分参数大家可能看的会难受,由于我很懒,直接粘贴过来的,所以了解一下重要部分就好了。
下面代码,获取到文件的请求体 ,重点是最后一部分,如果你用的也是OSS直传,注意addFormDataPart(“key”)一定要在addFormDataPart(“file”)之前。
val fileBody = RequestBody.create(MediaType.parse(getMimeType(file.absolutePath)), file)
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("OSSAccessKeyId", policy?.accessId)
.addFormDataPart("Signature", policyResult?.signature)
.addFormDataPart("callback", policy?.callback)
.addFormDataPart("key", policyResult?.key)
.addFormDataPart("policy", policyResult?.policy)
.addFormDataPart("success_action_status", "200")
.addFormDataPart("x-oss-forbid-overwrite", "true")
.addFormDataPart("file", file.name, fileBody)
.build()
然后看这段代码,实现回调监听,ProgressBody中的参数一 一对应,花括号里面的,是kotlin的lambda,这样就能将文件上传的进度回调展示了
//回调监听
val progressBody = ProgressBody(requestBody) { currentLength, ContentLength ->
progress(((currentLength.toFloat() / ContentLength.toFloat()) * 100).toInt().toString())
}
后面的这部分就是发起请求和响应了
val request = Request.Builder().post(progressBody).url(policy?.host).build()
val call: Call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call?, e: IOException?) {
uploadFail(e?.message)
}
override fun onResponse(call: Call?, response: okhttp3.Response?) {
if (response?.isSuccessful!!) {
val string = response.body().string()
val type = object : TypeToken<FileEntity>() {}.type
val file = gson.fromJson<FileEntity>(string, type)
complete(file)
} else {
complete(null)
}
}
})
效果图—我这里没有显示数,但是用的进度条展现的
到此就结束了,成功的完成了文件的上传和进度回调 。
如果帮到了您,给个好评哦!!