OkHttp3

作者: Ezea | 来源:发表于2018-06-06 16:53 被阅读79次

    引言

    最初我们进行HTTP请求时使用的是HttpURLConnection或者HttpClient,那么这两者都有什么优缺点呢?

    HttpClient是Apache基金会的一个开源网络库,功能十分强大,API数量众多,但正是由于庞大的API数量使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以Android团队在提升和优化HttpClient方面的工作态度并不积极。官方在Android 2.3以后就不建议用了,并且在Android 5.0以后废弃了HttpClient,在Android 6.0更是删除了HttpClient。

    HttpURLConnection是一种多用途、轻量极的HTTP客户端,提供的API比较简单,可以容易地去使用和扩展。不过在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能:

    private void disableConnectionReuseIfNecessary() {
        // 这是一个2.2版本之前的bug    
        if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
            System.setProperty("http.keepAlive", "false");
        }
    }
    

    因此一般推荐是在2.2之前使用HttpClient,因为其bug较少。在2.2之后推荐使用HttpURLConnection,因为API简单、体积小、有压缩和缓存机制,并且Android团队后续会继续优化HttpURLConnection。

    但是上面两个类库和OkHttp比起来就显得有些不足了,因为OkHttp不仅具有高效的请求效率,并且提供了很多开箱即用的网络疑难杂症解决方案。

    简介

    从Android 4.4开始google已经开始将源码中的HttpURLConnection替换为OkHttp,而在Android 6.0之后的SDK中google更是移除了对于HttpClient的支持,而现在流行的Retrofit同样是使用OkHttp进行再次封装而来的。

    OkHttp是一个快速、高效的网络请求库,它的设计和实现的首要目标便是高效,有如下特性:
    • 支持http2,使得对同一个主机发出的所有请求都可以共享相同的socket套接字连接;
    • 使用连接池来复用连接以减少延迟、提高效率;
    • 支持Gzip压缩响应体,降低传输内容的大小;
    • 支持Http缓存,避免重复请求;
    • 请求失败时会自动重试主机中的其他IP地址自动重定向;
    • 使用Okio来简化数据的访问与存储,提高性能;
    OkHttp3

    基本使用

    OKHttp3同步的使用方法

    OkHttpClient okHttpClient = new OkHttpClient();//1.定义一个client  
    Request request = new Request.Builder().url  ("http://www.baidu.com").build();//2.定义一个request  
    Call call = okHttpClient.newCall(request);//3.使用client去请求  
    try {  
        String result = call.execute().body().string();//4.获得返回结果  
        System.out.println(result);  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
    

    OKHttp3异步的使用方法

    OkHttpClient okHttpClient = new OkHttpClient();//1.定义一个client  
    Request request = new Request.Builder().url  ("http://www.baidu.com").build();//2.定义一个request  
    Call call = okHttpClient.newCall(request);//3.使用client去请求  
    call.enqueue(new Callback() {//4.回调方法  
        @Override  
        public void onFailure(Call call, IOException e) {  
    
        }  
    
        @Override  
        public void onResponse(Call call, Response response) throws IOException {  
            String result = response.body().string();//5.获得网络数据  
            System.out.println(result);  
        }  
    });  
    

    拦截器

    Application interceptors应用程序拦截器

    Interceptor appInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                //---------请求之前------------
                Response response = chain.proceed(request1);
                //---------请求之后------------
                return response;
            }
        };
    
    • 不需要担心比如重定向和重试的中间响应。
    • 总是被调用一次,即使HTTP响应结果是从缓存中获取的。
    • 监控应用程序的原始意图。不关心例如OkHttp注入的头部字段If-None-Match。
    • 允许短路,不调用Chain.proceed()。
    • 允许重试并多次调用Chain.proceed()。

    Network Interceptors网络拦截器

    Interceptor networkInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            //---------请求之前-----
            Log.d(TAG,"network interceptor:begin");
            Response  response = chain.proceed(request);
            Log.d(TAG,"network interceptor:end");
            return response;
        }
    };
    
    • 能够对中间的响应进行操作比如重定向和重试。
    • 当发生网络短路时,不调用缓存的响应结果。
    • 监控数据,就像数据再网络上传输一样。
    • 访问承载请求的连接Connection。

    配置拦截器

    okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(appInterceptor)//Application拦截器,主要拦截日志
                .addNetworkInterceptor(networkInterceptor)//Network拦截器,主要拦截请求头
                .build();
    

    缓存

    如果服务器支持缓存,请求返回的Response会带有这样的Header:Cache-Control, max-age=xxx,这种情况下我们只需要手动给okhttp设置缓存就可以让okhttp自动帮你缓存了。这里的max-age的值代表了缓存在你本地存放的时间。

    OkHttpClient okHttpClient = new OkHttpClient();  
    OkHttpClient newClient = okHttpClient.newBuilder()  
               .cache(new Cache(mContext.getCacheDir(), 10*1024*1024))  
               .connectTimeout(20, TimeUnit.SECONDS)  
               .readTimeout(20, TimeUnit.SECONDS)  
               .build();  
    

    如果服务器不支持缓存就可能没有指定这个头部,这种情况下我们就需要使用Interceptor来重写Respose的头部信息,从而让okhttp支持缓存。

    Interceptor interceptor = new Interceptor() {  
        @Override  
        public Response intercept(Chain chain) throws IOException {  
            Request request = chain.request();  
            Response response = chain.proceed(request);  
    
            String cacheControl = request.cacheControl().toString();  
            if (TextUtils.isEmpty(cacheControl)) {  
                cacheControl = "public, max-age=60";  
            }  
            return response.newBuilder()  
                    .header("Cache-Control", cacheControl)  
                    .removeHeader("Pragma")  
                    .build();  
        }  
    };  
    
        //设置缓存路径  
        File httpCacheDirectory = new File(mContext.getCacheDir(), "responses");  
        //设置缓存 10M  
        Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);  
    
        //创建OkHttpClient,并添加拦截器和缓存代码  
        OkHttpClient client = new OkHttpClient.Builder()  
                .addNetworkInterceptor(interceptor)  
                .cache(cache)  
                .build();  
    

    断点续传

                //服务器返回的内容的总长度
                final long contentLength = response.body().contentLength();
                //获取服务器返回的输入流
                InputStream inputStream = response.body().byteStream();
    
                //随机访问流
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                //在文件的什么位置开始追加写入  类似快进
                randomAccessFile.seek(downloadLen);
                byte[] bytes = new byte[1024];
                int len;
                //最主要就是下次读的时候从什么时候开始  
                while ((len = inputStream.read(bytes)) != -1) {
                    downloadLen = downloadLen + len;
                    randomAccessFile.write(bytes, 0, len);
                }
                inputStream.close();
                randomAccessFile.close();
    

    解析数据泛型

    private <T> T parseData(String json, OkHttpListener<T> okHttpListener) {
            //得到callback这个类上实现的所有接口包括泛型
            Type[] interfaces = okHttpListener.getClass().getGenericInterfaces();
            //interfaces[0] 取出数组中的第一个 getActualTypeArguments 获取真实的类型
            Type[] arguments = ((ParameterizedType) interfaces[0]).getActualTypeArguments();
            Gson gson = new Gson();
            T t = gson.fromJson(json, arguments[0]);
            return t;
    }
    

    大概的内容就到这儿了,希望小伙伴可以更深层次的挖掘!

    相关文章

      网友评论

          本文标题:OkHttp3

          本文链接:https://www.haomeiwen.com/subject/gbvbsftx.html