close
我們經常會有一些需要顯示上傳進度的時候吧?
比如說上傳大檔案、影片、相片之類的
若是 Loading icon 轉太久也會讓 user 不耐煩的
所以,今天要講用 okhttp 時,怎麼取得進度 percentage
基上上,要做到這件事情
我們需要自訂一個 RequestBody 才可以
先來看一般的上傳方式
先訂義好 API Service
@Multipart
@POST("/media/upload")
suspend fun mediaUpload(
@HeaderMap header: HashMap<String, String>,
@Part media: MultipartBody.Part
): UploadMediaRs
然後取得一般 requestBody 方式如下
file.asRequestBody(MediaType())
這樣就可以用這個 requestBody 去打 API 了
但我們想要有進度的話
就需要自訂一個,如下
ProgressRequestBody(
file,
MediaType(),
progressListener
)
可以看到我們多傳了一個 Listener 進去
這個就是為了回傳進度值的
接著看內部實作 ProgressRequestBody
class ProgressRequestBody(
private val file: File,
private val contentType: MediaType? = null,
private val progressListener: (percentage: Float) -> Unit
) : RequestBody() {
override fun contentType() = contentType
override fun contentLength() = file.length()
override fun writeTo(sink: BufferedSink) {
if (sink is Buffer) return
val source: Source = file.source()
val buf = Buffer()
var bytesWritten = 0L
try {
do {
// 一次塞 1KB Buffer
val readCount = source.read(buf, 1024L * 8)
// 記錄進度
bytesWritten += readCount
// 回傳 progress 小數點後兩位
progressListener(
BigDecimal(
bytesWritten.toDouble() / contentLength()*100
).setScale(2, RoundingMode.DOWN)
.toFloat()
)
// 讀完離開
if (readCount < 0) break
// 將 Buffer 寫入
sink.write(buf, readCount)
} while (true)
} catch (e: Exception) {
PLog.e(e, "ProgressRequestBody.writeTo:")
} finally {
source.close()
buf.clear()
}
}
}
很簡短的一個 Class
做的事就是,打開 File 然後一段段的寫入 Sink
在寫的過程中,回傳寫入的 percentage
大功告成
比較需要注意的是
writeTo 會被 call 兩次
這是因為我們用了 HttpLoggingInterceptor Body Level
它會 call writeTo 然後才是真正網路 call 的 writeTo
所以開頭我們才用一個 if 去擋掉一次 writeTo 喔
參考資料:
文章標籤
全站熱搜
留言列表