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博客

相关推荐
鬼蛟2 天前
ICAN_PARENT
okhttp
XiaoLeisj3 天前
Android 短视频项目首页开发实战:从广场页广告轮播与网格列表,到发现页分类、播单与话题广场的数据驱动实现
android·okhttp·mvvm·recyclerview·retrofit·databinding·xbanner 轮播
.豆鲨包6 天前
【Android】OkHttp的使用及封装
android·java·okhttp
华科易迅6 天前
Vue通过Ajax获取后台路由信息
vue.js·ajax·okhttp
studyForMokey7 天前
【Android面试】OkHttp & Retrofit 专题
android·okhttp·面试
fLDiSQV1W8 天前
springMVC-HTTP消息转换器与文件上传、下载、异常处理
网络协议·http·okhttp
Ttang2312 天前
Java爬虫:Jsoup+OkHttp实战指南
java·爬虫·okhttp
李庆政37012 天前
OkHttp的基本使用 实现GET/POST请求 authenticator自动认证 Cookie管理 请求头设置
java·网络协议·http·okhttp·ssl
无名-CODING12 天前
Java 爬虫进阶:动态网页、多线程与 WebMagic 框架实战
java·爬虫·okhttp
小李云雾13 天前
零基础-从ESS6基础到前后端联通实战
前端·python·okhttp·中间件·eclipse·html·fastapi