Okhttp系列文章:
你想要的系列:网络请求框架OkHttp3全解系列 - (一)OkHttp的基本使用
你想要的系列:网络请求框架OkHttp3全解系列 - (二)OkHttp的工作流程分析
你想要的系列:网络请求框架OkHttp3全解系列 - (三)拦截器详解1:重试重定向、桥、缓存(重点)
你想要的系列:网络请求框架OkHttp3全解系列 - (四)拦截器详解2:连接、请求服务(重点)
因为一直没有去详细了解okhttp原理,在网上找了很多文章,发现没有类似 郭霖的Glide系列那种 细致的详解系列,很不爽,决定自己整一下,应该会耗费不少时间,不过也是对自己的挑战,还有点兴奋呢。也希望和大家一起讨论。
预计okhttp系列有4篇,使用方法、流程分析、缓存和连接池、使用扩展及封装。
这是第一篇,按照惯例,就介绍基本的使用方法,比较简单。
好了,闲话少叙,开始!
所需 预备知识:现在Android中的网络请求框架,基本都是okhttp和Retrofit一统天下,而Retrofit又是以okhttp为基础,所以系统学习okhttp的使用和原理就很有必要了。
HTTP协议详解
HTTP请求报文和响应报文
【android|你想要的系列(网络请求框架OkHttp3全解系列 - (一)OkHttp的基本使用)】okhttp是由square公司开发,Android中公认最好用的网络请求框架,在接口封装上做的简单易用,GitHub地址。
它有以下默认特性:
- 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
- 使用连接池减少请求延时
- 透明的GZIP压缩减少响应数据的大小
- 缓存响应内容,避免一些完全重复的请求
一、引入 gradle引入依赖即可。
implementation 'com.squareup.okhttp3:okhttp:3.14.7'
implementation 'com.squareup.okio:okio:1.17.5'
3.14.x版本及以前的版本,采用Java语言编写,4.0.0以后采用kotlin语言;本系列文章中源码引自3.14.x版本,以Java语言讲解。
其中Okio库 是对Java.io和java.nio的补充,以便能够更加方便,快速的访问、存储和处理你的数据。OkHttp的底层使用该库作为支持。
另外,别忘了申请网络请求权限,如果还使用网络请求的缓存功能,那么还要申请读写外存的权限:
二、使用方式 基本使用步骤如下
- 构建客户端对象OkHttpClient
- 构建请求Request
- 生成Call对象
- Call发起请求(同步/异步)
2.1 get请求 以百度主页为例,进行Get请求:
OkHttpClient httpClient = new OkHttpClient();
String url = "https://www.baidu.com/";
Request getRequest = new Request.Builder()
.url(url)
.get()
.build();
Call call = httpClient.newCall(getRequest);
new Thread(new Runnable() {
@Override
public void run() {
try {
//同步请求,要放到子线程执行
Response response = call.execute();
Log.i(TAG, "okHttpGet run: response:"+ response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
首先,创建了OkHttpClient实例,接着用Request.Builder构建了Request实例并传入了百度主页的url,然后httpClient.newCall方法传入Request实例生成call,最后在子线程调用call.execute()执行请求获得结果response。
所以,使用OkHttp进行get请求,是比较简单的,只要在构建Request实例时更换url就可以了。
异步请求 有个问题,你可能注意到了,这里是放在子线程执行请求的,这是因为call.execute()是同步方法。想要在主线程直接使用而不用手动创建子线程可以嘛?当然可以,使用call.enqueue(callback)即可:
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}@Override
public void onResponse(Call call, Response response) throws IOException {
Log.i(TAG, "okHttpGet enqueue: onResponse:"+ response.body().string());
ResponseBody body = response.body();
String string = body.string();
byte[] bytes = body.bytes();
InputStream inputStream = body.byteStream();
}
});
call.enqueue会异步执行,需要注意的是,两个回调方法onFailure、onResponse是执行在子线程的,所以如果想要执行UI操作,需要使用Handler切换到UI线程。
取消请求 每一个Call只能执行一次(原因会在下篇流程分析中说明)。 如果想要取消正在执行的请求,可以使用call.cancel(),通常在离开页面时都要取消执行的请求的。
结果处理 请求回调的两个方法是指 传输层 的失败和成功。onFailure通常是connection连接失败或读写超时;onResponse是指,成功的从服务器获取到了结果,但是这个结果的响应码可能是404、500等,也可能就是200(response.code()的取值)。
如果response.code()是200,表示应用层请求成功了。此时我们可以获取Response的ResponseBody,这是响应体。从面看到,可以从ResponseBody获取string、byte[]、InputStream,这样就可以对结果进行很多操作了,比如UI上展示string(要用Handler切换到UI线程)、通过InputStream写入文件等等。
上面异步请求执行后 结果打印如下:
2020-05-04 21:52:56.446 32681-3631/com.hfy.androidlearning I/OkHttpTestActivity: okHttpGet run: response:
百度一下,你就知道 - 锐客网
文章图片
可见请求体重确实包含了姓名、电话、头像,并且注意到Content-Type值是 multipart/form-data。响应是200,说明请求成功了。
其他请求方式像put、header、delete,主要在构建Request时把get()或post()换成put()、header()、delete()就可以了,但一般在Android端很少用到。
2.4 请求配置项 先看几个问题:
- 如何全局设置超时时长?
- 缓存位置、最大缓存大小 呢?
- 考虑有这样一个需求,我要监控App通过 OkHttp 发出的 所有 原始请求,以及整个请求所耗费的时间,如何做?
这些问题,在OkHttp这里很简单。把OkHttpClient实例的创建,换成以下方式即可:
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.cache(new Cache(getExternalCacheDir(),500 * 1024 * 1024))
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String url = request.url().toString();
Log.i(TAG, "intercept: proceed start: url"+ url+ ", at "+System.currentTimeMillis());
Response response = chain.proceed(request);
ResponseBody body = response.body();
Log.i(TAG, "intercept: proceed end: url"+ url+ ", at "+System.currentTimeMillis());
return response;
}
})
.build();
这里通过OkHttpClient.Builder通过构建者模式设置了连接、读取、写入的超时时长,用cache()方法传入了由缓存目录、缓存大小构成的Cache实例,这样就解决了前两个问题。
还注意到,使用addInterceptor()方法添加了Interceptor实例,且重写了intercept方法。Interceptor意为拦截器,intercept()方法会在开始执行请求时调用。其中chain.proceed(request)内部是真正请求的过程,是阻塞操作,执行完后会就会得到请求结果ResponseBody,所以chain.proceed(request)的前后取当前时间,那么就知道整个请求所耗费的时间。上面chain.proceed(request)的前后分别打印的日志和时间,这样第三个问题也解决了。
具体Interceptor是如何工作,会在下一篇流程分析中介绍。
另外,通常OkHttpClient实例是全局唯一的,这样这些基本配置就是统一,且内部维护的连接池也可以有效复用(会在下一篇流程分析中介绍)。
全局配置的有了,单个请求的也可以有一些单独的配置。
Request getRequest = new Request.Builder()
.url("http://yun918.cn/study/public/file_upload.php")
.post(multipartBody)
.addHeader("key","value")
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
这个Request实例,
- 使用addHeader()方法添加了请求头。
- 使用cacheControl(CacheControl.FORCE_NETWORK)设置此次请求是能使用网络,不用缓存。(还可以设置只用缓存FORCE_CACHE。)
好了,okhttp的使用就讲这里了,总体还是比较简单的。下篇是okhttp的工作流程分析,将通过分析源码 了解okhttp的整体找工作流程,欢迎关注~
.
参考与感谢
Okhttp3基本使用
OkHttp使用详解
你的 点赞、评论、收藏、转发,是对我的巨大鼓励!
欢迎关注我的 公 众 号:
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-