絮语:
底层网络库也就是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。
使用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内部处理的问题啊