一、背景
使用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 = 0Lval buffer = ByteArray(4096)var bytesRead: Intvar lastProgress = 0while (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 = progresswithContext(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 = 0Lval buffer = ByteArray(4096)var bytesRead: Intvar lastProgress = 0while (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 = progresswithContext(Dispatchers.Main) {callback.onProgress(progress)}}if(!isDownloading){break}}
OkHttp超時設置可以查閱這篇博客:
Android OkHttp 框架超時設置詳解-CSDN博客