一种常见的OkHttp错误调用方式

棘手的问题

最近在工作中开发安卓项目。碰到了一个棘手的问题:代码在虚拟机中使用正常,但是在真机上一直出现网络问题。表现为网络联通性有规律的周期性,周期为2小时。

从图表中可以轻易看出,在2小时里连续的40分钟内,网络是正常的,但在其他时间段是异常,异常反馈是读取数据超时。一开始以为是网络环境的问题,但经过排查,发现问题并没有这么简单。

修改连接池存续时间

于是我尝试用HttpClient写了一个相同的接口,发现困扰我几周的问题,就消失了。难道是okHttp库的问题?但是okHttp是一个享誉世界的开源框架,应该不会出现这种错误。然后我找到了一篇文章。

记一次使用OkHttpClient大量请求导致SocketTimeoutException再到OutOfMemoryError的问题

里面提到要修改okhttp的线程池的存续时间。

于是我将存续时间改为10s,网络异常的问题就消失了。

builder.connectionPool(new ConnectionPool(5, 10, TimeUnit.SECONDS));

但这就真正解决了吗?

OkHttp的单例原则

我查了官网资料

Class OkHttpClient

里面提到了:

OkHttp performs best when you create a single OkHttpClient instance and reuse it for all of your HTTP calls. 
This is because each client holds its own connection pool and thread pools.
Reusing connections and threads reduces latency and saves memory.
Conversely, creating a client for each request wastes resources on idle pools.

这段话的意思是

“当你创建一个单例并且为所有的Http Calls复用这个单例时okHttp表现的最好。这是因为每个client都会保持自己的了连接池和线程池。复用连接池和线程池会减少延迟,节省内存。相反地,为每个请求创建一个Client将会浪费空闲池的资源。”

如果官网中的英文看不懂,可以看这篇文章,讲的内容是相似的:

OkHttp使用踩坑记录总结(一):OkHttpClient单例和长连接Connection Keep-Alive

反观我自己的代码,就是为每个请求申请一个新的client。每个client的维持时间长达5分钟(默认值)。这就阻塞了系统的连接池,最终导致网络异常。当系统 GC时,将资源回收,我的代码就有短暂的时间恢复网络正常。这就解释了网络异常的周期性。

当在网络环境好或者机器性能好时,这种调用方式的弊端还不会出现问题。但在弱网情况或机器性能差时,就会爆雷了。

问题的真正解决

依据OkHttp的单例原则 ,我重新修改了代码。这时即使连接池的存续时间仍然为5分钟,网络异常timeout的情况也不再出现。

 builder.connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES));

我在网络查找资料时,很多介绍OkHttp的文章却没有讲到这个OkHttp单例原则。包括我的同事之前写的代码也都没有使用这种原则。可见这种错误的调用方式是很常见的。亲爱的读者们,你们是否也犯了这种错误呢?欢迎留言讨论。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值