Android 使用OkHttp 下载文件失败问题定位和修复

一、背景

使用Okhttp下载文件时,存在失败情况,刚开始以为是网络问题,后面添加相关日志发现,是在网络波动比较大的情况下,被判为timeout超时,结束了下载任务。

二、解决方案

有问题的下载配置写法:

Kotlin 复制代码
注:这里只是展示配置下载的关键代码
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可以打印相关日志,判断失败原因

Kotlin 复制代码
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超时设置可以查阅这篇博客:

Android OkHttp 框架超时设置详解-CSDN博客

相关推荐
华农第一蒟蒻3 小时前
谈谈跨域问题
java·后端·nginx·安全·okhttp·c5全栈
一直向钱2 天前
android 基于okhttp的socket封装
android·okhttp
linuxxx1102 天前
ajax回调钩子的使用简介
okhttp
一直向钱3 天前
android 基于okhttp 封装一个websocket管理模块,方便开发和使用
android·websocket·okhttp
linuxxx1104 天前
ajax() 回调函数参数详解
前端·ajax·okhttp
linuxxx1106 天前
ajax与jQuery是什么关系?
ajax·okhttp·jquery
耀耀_很无聊8 天前
12_OkHttp初体验
okhttp
heeheeai8 天前
okhttp使用指南
okhttp·kotlin·教程
啦工作呢10 天前
ES6 promise-try-catch-模块化开发
android·okhttp
杨杨杨大侠13 天前
手把手教你写 httpclient 框架(三)- 动态代理与请求处理机制
java·okhttp·github