okhttp3.Call的enqueue()方法没有回到callback,可能是maxRequestsPerHost引起

 这段时间在全球范围的新型冠状病毒蔓延之下,忙忙碌碌之中,已有4个月的时间没写新的东西了,惭愧惭愧!

    这次是记录一下项目中遇到的一个在多次网络请求之后,网络接口没有回调的问题,下面说一下具体的来龙去脉。

    有一个文件下载的需求:最多同时支持3个下载任务。在明确了需求之后,就开始设计文件下载的方案了。

    1、网络请求、数据写入磁盘等需要异步处理;

    2、有可能存在比较大的文件,所以拆分为多个线程进行分段下载

    3、支持断点续传

    4、下载过程中的异常恢复,例如网络切换等等

    当然还有其他细节需要处理,例如进度更新等等,这里就不多说了,这次主要说说多线程下载过程中遇到的问题。我的网络请求是这样的,先创建一个OkHttpClient对象

 OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS);
        OkHttpClient mOkHttpClient = builder.build();

然后就是进行分段下载的网络请求了,当然在请求之前,要先计算好每段的起始位置和结束位置,我这里只阐述请求的部分:

// 设置分段下载的头信息
// start:起始位置,end:结束位置
Request request = new Request.Builder().header("RANGE", "bytes=" + start + "-" + end)
                .url(url)// 文件的网络地址
                .build();
// 异步请求
Call call = mOkHttpClient.newCall(request);
call.enqueue(callback);// 这个callback是okhttp3.Callback类型的对象

网络会回调上面的callback,这个callback里要实现两个方法:

  void onFailure(Call call, IOException e);
  void onResponse(Call call, Response response) throws IOException;

网络请求成功,则回调onResponse方法,在这里执行网络数据读取和写入磁盘就行了,若失败,则回调onFailure方法。感觉、似乎成功的曙光就在眼前了,结果在发起3个文件下载的任务后,发现只有5个网络请求回调了onResponse方法。正常情况下,3个文件下载任务,每个任务分3个请问进行分段下载,按说应该有9个回调onResponse方法。心塞啊。

    遇到问题,先从自身找原因吧。网络请求方式、分段的参数是没问题,那问题应该就在异步请求enqueue()上面了,跳进这个方法一步一步跟进去会发现,它会调用到okhttp3.Dispatcher类的promoteAndExecute方法:

private boolean promoteAndExecute() {
    ......
    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
 
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
        ......
    }
    ......
    return isRunning;
  }

  这个方法里的for循环体里有2个if语句,第一个if语句是说最大并发请求数不能超过maxRequests个,第二个if语句是说每个主机最大请求数不能超过maxRequestsPerHost个,这两个值的默认大小分别是

/** 最大并发请求数*/
private int maxRequests = 64;
/** 每个主机最大请求数*/
private int maxRequestsPerHost = 5;
    因为我下载的文件的主机地址是相同的,并且我发起了9个请求,于是我最多只能同时接收到5个回调。在明白的原因后,就要修改这个值,修改方法很简单:

mOkHttpClient.dispatcher().setMaxRequestsPerHost(9);

然后,就没有然后了,问题就此搞定了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值