`

Volley配置OkHttp的那些事儿

 
阅读更多

前言

打一来这公司,就使用的是volley框架进行网络请求。众所周知,目前最火的就是retrofit+okhttp+rxjava,只因一直在开发新功能,没有排开时间来替换,所以就将就着用了。可问题来了,最近老大总是抱怨android的网络请求慢,而且总是会超时,体验了一下公司ios客户端,网络请求确实快,也不会出现超时这种现象。怎么办呢?看下SD卡的网络错误日志,

com.android.volley.VolleyError.TimeoutError

看到这里,马上我们就会觉得偶尔出现这个是正常的,网络问题嘛,随时可能抽风。最多就是把网络连接超时时间设置长点。我们知道,volley默认的网络超时时间是2.5秒。所以,这对于弱网络环境下是不够的。于是,我把时间设置为了10s,如下

    //操作超时时间
public static final int CUD_SOCKET_TIMEOUT = 10000;
//最大重试请求次数
public static final int MAX_RETRIES = 0;
request.setRetryPolicy(new DefaultRetryPolicy(CUD_SOCKET_TIMEOUT,
MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
这里通过setRetryPolicy方法来设置,传入RetryPolicy参数,这里我们创建它的继承类DefaultRetryPolicy就好,超时时间设置为10s,重试次数为0,最好设置为0。如果设置为>0的次数,volley好像有个BUG,在弱网络情况下会进行两次请求。 
改好之后,这就完事了吗?NO,还是会间隔性的出现TimeOut,怎么办,再加长时间?我们也要考虑下用户体验,在10s内请求到还算好,超过10s用户体验就不好了。既然还是不行,那就用okhttp请求吧,要知道,volley使用的是HttpUrlConnect和HttpClient进行请求的。请求速度在网络框架里面并不是最好的,它适用轻量级数据高并发请求。那么为什么要换 okhttp呢,相对来说,okhttp请求速度还是比HttpUrlConnect更快的,因为oKHttp使用的请求类似于增强版的HTTPURLConnect。它的好处有如下几个: 
1、支持HTTP1.1/HTTP1.2/SPDY协议,要知道谷歌浏览器现在也用SPDY协议了。 
2,默认支持HTTPS请求,CA颁发的正式,自签名不行 
3,HTTP请求的header体和body体GZip压缩 
4,使用阻塞式线程池,优化网络请求队列 
5、支持拦截器,调试方便

所以,干嘛不换呢。那么,我们又该怎么配置Volley,使Volley使用OKHTTP请求呢,通过查看代码,我们发现,我们可以传递自己的HttpStack,那么就好办了,我们创建一个HttpStack的子类就好了。

接下来在build.gradle文件里面导入okhttp3。

compile 'com.squareup.okhttp3:okhttp:3.5.0'

compile('com.squareup.okhttp3:logging-interceptor:3.5.0')

compile 'com.squareup.okio:okio:1.7.0'

然后,我们在创建RequestQueue单例里面配置下就好了。

public class OkHttpStack implements HttpStack
{
    private OkHttpClient okHttpClient;
    public OkHttpStack()
    {
        okHttpClient = new OkHttpClient();
}
    @Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError
    {
        int timeOutMs = request.getTimeoutMs();
/*  HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                ZLogUtil.d("zgx", "OkHttp====headAndBody" + message);
            }
        });
        //包含header、body数据
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);*/
Dispatcher dispatcher = okHttpClient.dispatcher();
dispatcher.setMaxRequestsPerHost(15);
OkHttpClient.Builder okHttpBuilder = new OkHttpClient().newBuilder();
OkHttpClient resultOkHttpClient = okHttpBuilder
                .connectTimeout(timeOutMs, TimeUnit.MILLISECONDS)
                .readTimeout(timeOutMs,TimeUnit.MILLISECONDS)
                .writeTimeout(timeOutMs,TimeUnit.MILLISECONDS)
                .dispatcher(dispatcher)
                //.addInterceptor(loggingInterceptor)
.build();
Map<String, String> headerMaps = request.getHeaders();
Headers headers = Headers.of(headerMaps);
okhttp3.Request.Builder okHttpReqBuilder = new okhttp3.Request
                .Builder()
                .url(request.getUrl())
                .headers(headers);
setConnectionParametersForRequest(okHttpReqBuilder, request);
Response okHttpResponse = resultOkHttpClient
                .newCall(okHttpReqBuilder.build())
                .execute();
StatusLine responseStatus = new BasicStatusLine
                (
                        parseProtocol(okHttpResponse.protocol()),
okHttpResponse.code(),
okHttpResponse.message()
                );
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromOkHttpResponse(okHttpResponse));
Headers responseHeaders = okHttpResponse.headers();
        for (int i = 0, len = responseHeaders.size(); i < len; i++)
        {
            final String name = responseHeaders.name(i), value = responseHeaders.value(i);
            if (name != null)
            {
                response.addHeader(new BasicHeader(name, value));
}
        }
        return response;
}

    private static HttpEntity entityFromOkHttpResponse(Response r) throws IOException
    {
        BasicHttpEntity entity = new BasicHttpEntity();
ResponseBody body = r.body();
entity.setContent(body.byteStream());
entity.setContentLength(body.contentLength());
entity.setContentEncoding(r.header("Content-Encoding"));
        if (body.contentType() != null)
        {
            entity.setContentType(body.contentType().type());
}
        return entity;
}

    @SuppressWarnings("deprecation")
    private static void setConnectionParametersForRequest
(okhttp3.Request.Builder builder, Request<?> request)
            throws IOException, AuthFailureError
    {
        switch (request.getMethod())
        {
            case Request.Method.DEPRECATED_GET_OR_POST:
                byte[] postBody = request.getPostBody();
                if (postBody != null)
                {
                    builder.post(RequestBody.create
                            (MediaType.parse(request.getPostBodyContentType()), postBody));
}
                break;
            case Request.Method.GET:
                builder.get();
                break;
            case Request.Method.DELETE:
                builder.delete();
                break;
            case Request.Method.POST:
                builder.post(createRequestBody(request));
                break;
            case Request.Method.PUT:
                builder.put(createRequestBody(request));
                break;
            case Request.Method.HEAD:
                builder.head();
                break;
            case Request.Method.OPTIONS:
                builder.method("OPTIONS", null);
                break;
            case Request.Method.TRACE:
                builder.method("TRACE", null);
                break;
            case Request.Method.PATCH:
                builder.patch(createRequestBody(request));
                break;
            default:
                throw new IllegalStateException("Unknown method type.");
}
    }

    private static ProtocolVersion parseProtocol(final Protocol p)
    {
        switch (p)
        {
            case HTTP_1_0:
                return new ProtocolVersion("HTTP", 1, 0);
            case HTTP_1_1:
                return new ProtocolVersion("HTTP", 1, 1);
            case SPDY_3:
                return new ProtocolVersion("SPDY", 3, 1);
            case HTTP_2:
                return new ProtocolVersion("HTTP", 2, 0);
}

        throw new IllegalAccessError("Unkwown protocol");
}

    private static RequestBody createRequestBody(Request r) throws AuthFailureError
    {
        final byte[] body = r.getBody();
        if (body == null) return null;
        return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
}
}

这样,就配置好了Volley使用OkHttp请求了。接下来奇葩的事就出来了。

 publicvoidinitialize(Context context) { if(mRequestQueue==null) mRequestQueue = Volley.newRequestQueue(context,new OkHttpStack()); mRequestQueue.start(); }

1,在公司wifi,android访问云端还是会出现间隔性的TimeoutError问题,而且是毫无规律的,ios访问就不会有这个现象 
2、在家用wifi,访问就确实是比以前快多了。 
3、使用手机数据连接3G或者4G访问也快。

这里记录下自己尝试的方法

1、优化网络请求频率,要知道,没有配置okhttp的情况下,volley在弱网的情况下,网络延时还是挺大的,优化的并不够好。 
2,使用fidder手机抓包,抓包的时候不会出现这个问题。 
3,ping云端ip,看是否会出现timeOutError问题,可以使用oneAPM或者jmeter压力测试。 
4,猜想公司使用的是二级域名,后来发现公司使用wifi和家用wifi没有什么区别的,都是AP+路由。 
5、是否和HTTPS和HTTPDNS有关,后来发现也没有关系。 
6、通过Dispatcher加大okhttp每秒的最大请求数。

经过多种方式尝试,结果并没有解决公司wifi情况下这种间隔性超时的问题。最后,经过各种google搜索,终于找到一篇博客,和这种情况一模一样的,阿里云ECS上APP访问异常或超时

原因:
导致请求阿里云ECS上的APP访问超时或访问慢,是由于移动端发送过来的TCP包的时间戳是乱的,所以服务器将这些包给丢弃了。

解决方案:
        #vim /etc/sysctl.config
net.ipv4.tcp_tw_recycle = 0  // net.ipv4.tcp_tw_recycle 设置为1,则开启!设置为0为关闭!记录时间戳
#sysctl  -p
分享到:
评论

相关推荐

    volley和okhttp的jar包

    Volley和OkHttp是两种广泛使用的网络请求库,在Android应用开发中扮演着重要角色。Volley是由Google开发的网络通信库,它强调了快速响应和轻量级的特性,适合处理大量的小数据请求,如获取JSON数据或者图片加载。而...

    volley和okhttp的jar包含volley源码

    - 将OkHttp的OkHttpClient实例配置给Volley的HttpStack,这样Volley就会利用OkHttp进行网络通信。 4. 关于提供的文件: - okhttp-urlconnection-2.2.0.jar:这是OkHttp的URLConnection适配器,用于在使用 ...

    volley_okhttp_retrofit三种请求方式的基本用法

    本篇文章将详细讲解Volley、OkHttp和Retrofit这三种常用的网络请求库的基本用法,帮助开发者更好地理解和选择适合自己的请求方式。 **Volley** Volley是由Google官方推出的网络请求库,它专注于Android平台,提供...

    Volley用OkHttp3作为底部的框架的一个解决方案

    Volley用OkHttp3作为底部的框架的一个解决方案。Android6.0删除了一些org.apache.http包中的一些类,所以网上的一些解决方案就会有一点不太合适。下面是我自己写了一个解决方案。

    Volley,Okhttp,Retrofit网络请求事例

    本篇文章将详细探讨三个流行的网络库:Volley、OkHttp和Retrofit,它们各自的特点、用法以及如何进行GET和POST请求。 首先,Volley是由Google推出的网络请求库,其设计目标是提供一个高效、易用的网络请求框架。...

    Android代码-基于Volley、OKHTTP的Rest API请求框架

    A http request engine based on Volley and OkHttp, giving up Apache HttpClient request. supports image loading, restful api requesting, and file downloading. READ MORE Dependency binary on jcenter ...

    Volley-OkHttp-Android:这是Volley的克隆,并进行了相关更改以使其可与Square的OkHttp库一起使用。 它还集成了Jackson,以提供方便的对象模型

    Volley-OkHttp-Android 该库是一个Android网络抽象库,由Volley,OkHttp和Jackson组合而成,并带有一些胶水将它们粘在一起。 如果您需要执行请求,尤其是返回JSON的请求,那么这是一个很好的起点。

    Volley,xUtils,okHttp第三方网络框架jar包

    为了简化这一过程,开发者通常会使用第三方网络框架,例如Volley、xUtils和OkHttp。这些框架提供了高效、易用的API,帮助开发者快速实现网络数据的获取和传输。接下来,我们将详细讨论这三个著名的网络库。 1. **...

    煎蛋项目okhttp_volley

    《煎蛋项目OkHttp与Volley的深度解析》 在Android开发中,网络请求是必不可少的一部分,本项目“煎蛋项目okhttp_volley”正是基于OkHttp和Volley这两个强大的网络库来构建的。本文将深入探讨这两个组件的原理、优势...

    Volley-XUtils-OkHttp三种方式实现单张多张图片上传

    本篇文章将深入探讨如何利用Volley、XUtils和OkHttp这三种流行的网络库来实现单张或多张图片的上传。下面我们将逐一介绍每种方法的关键步骤和注意事项。 ### Volley 图片上传 Volley是Google推出的网络请求库,以...

    RxVolley = Volley + RxJava + OkHttp(OkHttp3.0).rar

    RxVolley是一个基于Volley的网络请求库;同时支持RxJava;可以选择使用OKHttp替代默认的 HttpUrlConnection 做网络请求;可以选择使用图片加载功能(复用的网络请求将有效减少apk体积);移除了原Volley的 HttpClient ...

    Android代码-RxVolley,支持RxJava,OKhttp,内置了一个RxBus,移除了httpclient相关API

    &gt; RxVolley = Volley RxJava OkHttp 中文帮助 Retrofit? No, I like Volley. RxVolley is modified Volley. Removed the HttpClient, and support RxJava. If you are building with Gradle, simply add the ...

    eocboxVolleyBox:集成了Android Volley和OkHttp,可轻松实现联网

    OkHttp 适用于Android和Java应用程序的HTTP&SPDY客户端。 HTTP / 2和SPDY支持允许对同一主机的所有请求共享一个套接字。 连接池可减少请求延迟(如果SPDY不可用)。 透明的GZIP缩小了下载大小。 响应缓存可以...

    Android-okhttp封装

    相比其他网络库,如HttpURLConnection或Volley,OkHttp提供了以下几点优势: 1. **连接池**:OkHttp可以复用先前建立的TCP连接,减少网络延迟,提高响应速度。 2. **缓存机制**:OkHttp内置了缓存机制,可以自动...

    Android-itisavolleyokhttp的网络请求框架

    通过阅读和理解这些代码,开发者可以更好地理解和应用这种网络请求解决方案,同时也能灵活地根据项目需求调整OkHttp和Volley的配置。 总的来说,Android的Volley和OkHttp的结合使用,为开发者提供了高效、安全且...

    Android开发 okhttp网络请求使用demo,包括上传文件方法封装

    相较于其他网络库,如HttpURLConnection或Volley,OkHttp提供了更好的性能和更低的内存占用。 **1. OkHttp的初始化** 在使用OkHttp前,我们需要先创建一个OkHttpClient实例。这个实例可以配置各种参数,比如超时...

    Android代码-OkHttp-Volley-Gson

    Android Networking I: OkHttp, Volley and Gson This is a sample app which demonstrates and shows what it's explained in a Medium article about networking in Android. Check out the next article for ...

    volley访问https需要用到的类与库

    3. 配置 VolleyRequestQueue:现在,我们需要在初始化 VolleyRequestQueue 时使用我们的自定义 HttpStack。以下是如何做到这一点的示例代码: ```java public class VolleyToolbox { public static void init...

    AndroidNetworkDemo:演示演示如何在OkHttp和https上使用Volley

    Android Network DemoThis demo shows how to use volley with OkHttp and security your api with https.本文同步发于代码结构说明tools 文件夹下是相关的工具 dumps.sh 是一个导出证书并转换成 BKS 存储的完整脚本...

Global site tag (gtag.js) - Google Analytics