OkHttp3

引言

最初我们进行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_第1张图片
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 parseData(String json, OkHttpListener 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)