OkHttp的用法在此不讲
一些提前准备的代码
typealias ProgressListener = (progress: Int)->Unit
下载进度监听:对ResponseBody的包装,本质是对Source包装,在其read方法中实时获取已读取字节大小
/**
* 在Source.read()中监听下载进度
*/
class ProgressResponseBody(
private val responseBody: ResponseBody,
private val l: ProgressListener
): ResponseBody() {
private val bufferedSource: BufferedSource by lazy {
getWrappedSource(responseBody.source()).buffer()
}
private var progressListener: ProgressListener? = null
override fun contentLength(): Long = responseBody.contentLength()
override fun contentType(): MediaType? = responseBody.contentType()
override fun source(): BufferedSource = bufferedSource
private fun getWrappedSource(source: Source): Source = object : ForwardingSource(source) {
private var bytesRead = 0L
private val contentLength by lazy {
contentLength() //避免重复调用
}
override fun read(sink: Buffer, byteCount: Long): Long {
val bytes = super.read(sink, byteCount)
if (bytes != -1L)
bytesRead += bytes
//进度监听回调
val progress = bytesRead * 100 / contentLength
progressListener?.invoke(progress.toInt())
return bytes
}
}
}
使用
OkHttpClient.Builder()
.addNetworkInterceptor {
val response = it.proceed(it.request())
val body = response.body() ?: return@addNetworkInterceptor response
val pBody = ProgressResponseBody(body) { progress ->
//利用progress值更新UI或处理其它业务逻辑
}
response.newBuilder()
.body(pBody)
.build()
}
上传进度监听:对RequestBody的包装,本质是对Sink包装,在其writeTo方法中实时获取已写入字节大小
/**
* 在Sink.write()中监听上传进度
*/
class ProgressRequestBody(
private val requestBody: RequestBody,
private val l: ProgressListener
): RequestBody() {
private var progressListener: ProgressListener? = null
private lateinit var bufferedSink: BufferedSink
override fun contentType(): MediaType? = requestBody.contentType()
override fun contentLength(): Long = requestBody.contentLength()
override fun writeTo(sink: BufferedSink) {
if (!this::bufferedSink.isInitialized)
bufferedSink = getWrappedSink(sink).buffer()
requestBody.writeTo(bufferedSink)
bufferedSink.flush()
}
private fun getWrappedSink(sink: Sink): Sink = object : ForwardingSink(sink) {
private var bytesWritten = 0L
private val contentLength by lazy {
contentLength()
}
override fun write(source: Buffer, byteCount: Long) {
super.write(source, byteCount)
bytesWritten += byteCount
val progress = bytesWritten * 100 / contentLength
progressListener?.invoke(progress.toInt())
}
}
}
使用
val file = File(path)
val fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), file)
//最终要post的requestBody
val requestBody = ProgressRequestBody(fileBody) { progress ->
//利用progress值更新UI或处理其它业务逻辑
}