android之底层网络库

絮语:

底层网络库也就是jar,是其他公司根据HTTP协议来封装,HTTP协议实现了网络传输,但是只是理论上,要把它变成实践的,具体的代码,需要进行封装,就诞生了我们可看到可触摸可使用的底层网络库。这些网络库都是符合HTTP规范来封装,所以肯定现实了网络的传输。但是各个公司封装HTTP协议有各个公司的思想,习惯。因此各个底层网络库数据传输的效率,线程的切换等等都有不同。

一、HttpClient(废弃了)

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。但是android5.0的时候已经被废弃了,等到android6.0的时候就把它系统中移除出去了。为啥要移除了?因为现在Apache已经停止维护了,后续就没有更新 了,所以谷歌在就移除了这个包,如果想要用以前的版本,需要导入HttpClient

 二、功能介绍

以下列出的是 HttpClient 提供的主要的功能,要知道更多详细的功能可以参见 HttpClient 的主页。

(1)实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)

(2)支持自动转向

(3)支持 HTTPS 协议

(4)支持代理服务器

二、HttpUrlConnection(底层改成okhttp3)

Sun公司提供的库,也是Java的标准类库java.net中的一员,但这个类什么都没封装,用起来很原始,若需要高级功能,则会显得不太方便,比如重访问的自定义,会话和cookie等一些高级功能。 URLConnection是个抽象类,它有两个直接子类分别是HttpURLConnection和JarURLConnection。另外一个重要的类是URL,通常URL可以通过传给构造器一个String类型的参数来生成一个指向特定地址的URL实例。每个 HttpURLConnection 实例都可用于生成单个请求,但是其他实例可以透明地共享连接到 HTTP 服务器的基础网络。请求后在 HttpURLConnection 的 InputStream 或 OutputStream 上调用 close() 方法可以释放与此实例关联的网络资源,但对共享的持久连接没有任何影响。如果在调用 disconnect() 时持久连接空闲,则可能关闭基础套接字从Android4.4开始HttpURLConnection的底层实现采用的是okHttp。

三、OkHttp3

1.介绍

官网 

http://square.github.io/okhttp/

参考文献:http://www.jianshu.com/p/27c1554b7fee

android网络框架之OKhttp

一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square

公司贡献(该公司还贡献了Picasso)[2] 当前推出了Okhttp3用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,现在已经打不出来

2.OKhttp的优势

1. Http/2支持多路复用

2. 采用连接池减少请求延时

3. 支持GZIP压缩

4. 响应缓存

5. 支持websocket

6. 多ip切换(连接失败并且服务器有多ip)

 

3.OKhttp的功能


get,post请求[3] 

文件的上传下载[3] 

加载图片(内部会图片大小自动压缩)[3] 

支持请求回调,直接返回对象、对象集合[3] 

支持session的保持[3]  

 

4.总体流程

整个流程是,通过OkHttpClient将构建的Request转换为Call,然后在RealCall中进行异步或同步任务,最后通过一些的拦截器interceptor发出网络请求和得到返回的response。

android之底层网络库填写图片摘要(选填) 

使用OkHttp的时候我们都会创建一个OkHttpClient对象:

 OkHttpClient client = new OkHttpClient();

默认构造

final Dispatcher dispatcher;  //分发器

    final Proxy proxy;  //代理

    final List protocols; //协议

    final List connectionSpecs; //传输层版本和连接协议

    final List interceptors; //拦截器

    final List networkInterceptors; //网络拦截器

    final ProxySelector proxySelector; //代理选择

    final CookieJar cookieJar; //cookie

    final Cache cache; //缓存

    final InternalCache internalCache;  //内部缓存

    final SocketFactory socketFactory;  //socket 工厂

    final SSLSocketFactory sslSocketFactory; //安全套接层socket 工厂,用于HTTPS

    final CertificateChainCleaner certificateChainCleaner; // 验证确认响应证书 适用 HTTPS 请求连接的主机名。

    final HostnameVerifier hostnameVerifier;    //  主机名字确认

    final CertificatePinner certificatePinner;  //  证书链

    final Authenticator proxyAuthenticator;     //代理身份验证

    final Authenticator authenticator;      // 本地身份验证

    final ConnectionPool connectionPool;    //连接池,复用连接

    final Dns dns;  //域名

    final boolean followSslRedirects;  //安全套接层重定向

    final boolean followRedirects;  //本地重定向

    final boolean retryOnConnectionFailure; //重试连接失败

    final int connectTimeout;    //连接超时

    final int readTimeout; //read 超时

    final int writeTimeout; //write 超时

 

在这些声明的对象中可以看出来,几乎所有用到的类都和

OkHttpClient有关系。事实上,你能够通过它来设置改变一些参数,因为他是通过

建造者模式

实现的,因此你可以通过

builder()来设置。如果不进行设置,在

Builder中就会使用默认的设置:

 

真正的流程要从里面的

newCall()方法中说起:

 

        @Override

        public Call newCall(Request request) {

            return new RealCall(this, request);

        }

 

当通过

建造者模式

创建了

Request之后(这个没什么好说),紧接着就通过下面的代码来获得

Response大家还记得上面做

GET请求时的这句代码吧:

Response response = client.newCall(request).execute();这就代码就开启了整个GET请求的流程:

 

RealCall:真正的请求执行者。

 

 

5.简单用法
添加依赖

//okhttp3

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

//gson

implementation 'com.google.code.gson:gson:2.8.0'

2.同步网络请求

就是不开子线程, 等到网络数据加载完毕之后才执行下一步

它会报错,要开启子线程才不会

 

 

private void loadDataSync() {

    new Thread(new Runnable() {

        @Override

        public void run() {

            String url="http://10.0.2.2:8080/christ/home.json";

            //创建请求

            Request request=new Request.Builder().get().url(url).build();

            //创建okhttp客户端

            OkHttpClient okHttpClient=new OkHttpClient();

            try {

                Response response = okHttpClient.newCall(request).execute();//同步网络请求

                //同步请求是,不开子线程,等待到网络下载完毕之后再执行下去

                String result = response.body().string();

                Log.d("christ","---"+result);

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }).start();

}

 

3.异步发送网络请求

在okhttp内部的线程中执行网络请求

不需要等待网络加载数据才执行下一步,结果是先打印

D/christ: textOkHttp 

后打印这个http://10.0.2.2:8080/...

 

private void loadDataAsSync() {

    String url="http://10.0.2.2:8080/christ/home.json";

    //创建请求

    final Request request=new Request.Builder().get().url(url).build();

    //创建okhttp客户端

    OkHttpClient okHttpClient=new OkHttpClient();

    //异步网络请求,不需要等到网络返回结果,就可以执行后续的代码

    okHttpClient.newCall(request).enqueue(new Callback() {

       

        @Override

        public void onFailure(Call call, IOException e) {

        }

       

        @Override

        public void onResponse(Call call, Response response) throws IOException {

            Log.d("christ",""+Thread.currentThread().getName());

        }

    });

    Log.d("christ","text");

}

4中括号字符串数组解析list集合

private void loadStringArray() {

    String url="http://10.0.2.2:8080/christ/stringarray.json";

    //创建请求

    final Request request=new Request.Builder().get().url(url).build();

    //创建okhttp客户端

    OkHttpClient okHttpClient=new OkHttpClient();

    okHttpClient.newCall(request).enqueue(new Callback() {

        @Override

        public void onFailure(Call call, IOException e) {

        }

       

        @Override

        public void onResponse(Call call, Response response) throws IOException {

            String result=response.body().string();

            Type type=new TypeToken>(){}.getType();

            List list = mGson.fromJson(result, type);

            for (int i = 0; i < list.size(); i++) {

                Log.d("christ",""+list.get(i));

            }

        }

    });

    Log.d("christ","text");

}

5.中括号数组的解析为一个bean

private void loadNewsArray() {

    String url="http://10.0.2.2:8080/christ/array.json";

    //创建请求

    final Request request=new Request.Builder().get().url(url).build();

    //创建okhttp客户端

    OkHttpClient okHttpClient=new OkHttpClient();

    okHttpClient.newCall(request).enqueue(new Callback() {

        @Override

        public void onFailure(Call call, IOException e) {

        }

       

        @Override

        public void onResponse(Call call, Response response) throws IOException {

            String result=response.body().string();

            Type type=new TypeToken>(){}.getType();

            List list = mGson.fromJson(result, type);

            for (int i = 0; i < list.size(); i++) {

                Log.d("christ",""+list.get(i).getTitle());

            }

        }

    });

    Log.d("christ","text");

}

6.注意的问题

String result=response.body().string();Log.d("christ",""+response.body().string());

结果不能获取两次,为啥呢?因为返回的结果是在存储在缓冲中,只能拿一次,拿了之后就没有了,这是okHttp内部处理的问题啊