如何通过OkHttp3精准获取Android应用中响应内容下载时长?
如何用OkHttp3精准获取响应内容的下载时长
我来帮你梳理下这个问题,先拆解清楚OkHttp的时间戳逻辑,再给你正确的实现方案。
首先得明确你之前的思路为什么会出现数值不稳定的情况:当chain.proceed(request)返回Response对象时,OkHttp只完成了响应头的接收,响应体的内容还在网络流里,并没有完全下载到本地。你此时取System.currentTimeMillis()和receivedResponseAtMillis()的差值,其实只是从响应头接收完成到你拿到Response对象的极短时间,根本不是响应内容的实际下载时长。
先搞懂OkHttp的几个时间戳含义
sentRequestAtMillis():请求头完全发送到网络的时间点receivedResponseAtMillis():响应头完全从网络接收的时间点
这两个的差值是请求往返总耗时(包含请求发送、服务器处理、响应头返回的时间),确实不包含响应体的下载时间。
正确的实现思路
要拿到纯响应内容的下载时长,你需要在响应头接收完成后,开始读取响应体的时刻到响应体完全读取完毕的时刻之间计时。因为只有读取完响应体的所有字节,才代表内容真正下载完成。
这里要注意:OkHttp的响应体流只能读取一次,所以读取后需要重新构建响应体,避免影响后续的业务逻辑。
完整代码示例
@Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); // 响应头接收完成的时间,也就是响应体下载开始的时间 long contentDownloadStart = response.receivedResponseAtMillis(); long contentDownloadEnd; ResponseBody originalBody = response.body(); if (originalBody != null) { // 读取响应体所有内容,触发实际下载 byte[] bodyBytes = originalBody.bytes(); contentDownloadEnd = System.currentTimeMillis(); // 重新构建响应体,保证后续流程能正常读取 ResponseBody newBody = ResponseBody.create( originalBody.contentType(), originalBody.contentLength(), ByteString.of(bodyBytes).source() ); response = response.newBuilder().body(newBody).build(); } else { // 无响应体的情况,下载时长为0 contentDownloadEnd = contentDownloadStart; } // 计算时间 double contentDownloadTimeSecs = (contentDownloadEnd - contentDownloadStart) / 1000.0; double requestRoundTripTimeSecs = (contentDownloadStart - response.sentRequestAtMillis()) / 1000.0; // 这里可以根据需求打印或上报数据 Log.d("BandwidthStats", String.format("URL: %s | 往返耗时: %.2fs | 内容下载耗时: %.2fs", request.url().toString(), requestRoundTripTimeSecs, contentDownloadTimeSecs)); return response; }
额外注意事项
- 大响应体的处理:如果你的接口返回大文件或大JSON,用
bytes()或string()读取到内存可能会引发OOM。这种情况下可以用流的方式边读边计时,比如:InputStream inputStream = originalBody.byteStream(); contentDownloadEnd = System.currentTimeMillis(); // 循环读取直到流结束 byte[] buffer = new byte[4096]; while (inputStream.read(buffer) != -1) { // 可以将字节写入文件或做其他处理 } contentDownloadEnd = System.currentTimeMillis(); - 网络节流测试:测试时尽量用较大的响应体(比如几MB的文件),这样内容下载时长会更明显,数值也会更稳定。小响应体的话时间差太小,容易被系统调度误差影响。
内容的提问来源于stack exchange,提问作者Sanat
相关产品推荐
相关产品推荐

