一、背景
使用Okhttp下载文件时,存在失败情况,刚开始以为是网络问题,后面添加相关日志发现,是在网络波动比较大的情况下,被判为timeout超时,结束了下载任务。
二、解决方案
有问题的下载配置写法:
注:这里只是展示配置下载的关键代码
val client = OkHttpClient()
val request = Request.Builder().url(downUrl).build()
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
callback.onFailure("Failed to download: ${response.code()}")
// throw IOException("Failed to download: ${response.code()}")
}
response.body()?.use { body ->
val inputStream = body.byteStream()
val outputStream = FileOutputStream(file)
val totalBytes = body.contentLength()
var bytesDownloaded = 0L
val buffer = ByteArray(4096)
var bytesRead: Int
var lastProgress = 0
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
bytesDownloaded += bytesRead
// 更新进度(确保回调到主线程)
val progress = (bytesDownloaded.toFloat() / totalBytes * 100f).toInt()
if (progress > lastProgress) {
lastProgress = progress
withContext(Dispatchers.Main) {
callback.onProgress(progress)
}
}
if(!isDownloading){
break
}
}
优化修改后的写法:
通过EventListener中的callFailed可以打印相关日志,判断失败原因
val client = OkHttpClient.Builder()
.callTimeout(0, TimeUnit.SECONDS)//这里配置永不超时,也可以根据需要设置超时时间
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
.eventListener(object:EventListener() {
override fun callFailed (call: Call, ioe:IOException) {
// 记录失败日志
Log.d("AAAAA",">>>>>callFailed:${ioe.message},,cause:${ioe.cause}")
callback.onFailure("下载失败:${ioe.message}")
}
})
.build()
val request = Request.Builder().url(downUrl).build()
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
callback.onFailure("Failed to download: ${response.code()}")
// throw IOException("Failed to download: ${response.code()}")
}
response.body()?.use { body ->
val inputStream = body.byteStream()
val outputStream = FileOutputStream(file)
val totalBytes = body.contentLength()
var bytesDownloaded = 0L
val buffer = ByteArray(4096)
var bytesRead: Int
var lastProgress = 0
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
bytesDownloaded += bytesRead
// 更新进度(确保回调到主线程)
val progress = (bytesDownloaded.toFloat() / totalBytes * 100f).toInt()
if (progress > lastProgress) {
lastProgress = progress
withContext(Dispatchers.Main) {
callback.onProgress(progress)
}
}
if(!isDownloading){
break
}
}
OkHttp超时设置可以查阅这篇博客: