okhttp缓存设置
⑴ okhttp3封装工具类怎么删除缓存
系统数据类——系统文件存储相关文件夹1、.android_secure:官方app2sd的产物,存储了相关的软件使用认证验证,删除之后SD卡中的软件将无法使用。2、Android:存放重要的程序数据,比如google:map的地图缓存,误删掉后地图还需重新下载。3、backups:包含重要的备份文件,比如联系人导出到SD卡会导入到此文件夹。4、bugtogo:系统出现问题的时候会形成一些报告文件,存放在此文件夹。5、data:缓存数据文件夹,与Android类似。例如,“截图助手”截图保存在data\com.edwardkim.android.screenshotitfull\screenshots里。6、LOST.DIR:卡上丢失或出错的文件会移动到这里,此目录删了会自动生成。7、SystemAppBackup:SystemAppremove(深度卸载)备份系统文件后,备份文件保存的目录。8、bugreports:升级系统或刷机,系统和程序发生兼容错误报告列表(包括内存使用全部内容)将保存在这个文件,重起机器可以删除。9、.keepsafe:隐藏类的软件、加密保存文件地址存放于此。10、.thumbs:浏览或使用某一软件,以及使用某一文件夹后用于记录次数和内容的文件,随机产生,需要定期不断清除,长时间不清理会大量占用储存卡的有效空间。11、openfeint:打开联接网络后的一个启动程序,它广泛植入移动类平台发布的软件或游戏,是更新下载或评论反馈信息的记录地址,可删除。12、com:播放类软件在收看播放影视节目生成的文件将存放于此,可以对制作方反映回馈信息,可以删除。13、Download(download):大写字母的是网络联接下载文件目录,小写字母的是手机自身(蓝牙,近场等)存放下载传输文件,不要误删。系统工具类——系统自带工具相关文件夹1、albumart:音乐专辑封面的缓存文件夹。2、albums:相册缩略图的缓存文件夹。3、cmp:音乐的缓存文件夹。4、Playlists:播放列表的缓存文件夹。5、DCIM:相机随机缓存文件夹,记录功能设置的参数,需要及时清理。一些第三方相机软件拍出的相片也会保存在这里,比如360或晕影相机等。6、VPN:VPN数据的缓存目录。7、Mydocuments:手机启用各种程序任务记录的文档,需要定期清除,长时间不清理会占用SD卡较大内存。8、.nomedia:手机中隐藏的音频、图片文件夹都会在这里显示,可以自设在相关文件夹中。9、media:使用电话通话录音软件或在线浏览视频等媒体产生的音频文件记录存档将保存在此。10、.medieval_software:启用蓝牙传输软件时,记录任务保存文件的目录。11、extracted:解压缩软件默认的解压目录。三方应用类1、.mobo:Moboplayer的缓存文件。2、.QQ:QQ的缓存文件,需要定期清除。3、.quickoffice:quickoffice的缓存文件。4、.switchpro:switchprowidget(多键开关应用)的缓存文件。5、.ucdlres:UC迅雷的缓存文件。6、:掌上网络、网络输入法之类程序的缓存文件夹。7、etouch:易行的缓存文件夹。8、documents:DocumentsToGo的相关文件夹。9、gameloft:gameloft游戏数据包存放的文件夹。10、handcent:handcent(超级短信)数据文件夹。11、handyCurrency:货币汇率相关的文件夹,装了handycalc(科学计算器)之后才会有。12、ireader:ireader的缓存文件夹。13、KingReader:开卷有益的缓存文件夹:下载的文件和应用都在这儿:删除时留意看清14、LazyList:Applanet的缓存目录,慎重使用。15、moji:墨迹天气的缓存目录。16、MusicFolders:poweramp产生的缓存文件夹。17、openfeint:openfeint的缓存文件夹。18、Picstore:图片浏览软件建立的一个目录。19、renren:人人网客户端的缓存文件夹。20、screenshot:截屏图片保存的目录。21、ShootMe:shootme截屏后图片文件保存的目录。22、SmartpixGames:SmartpixGames出品游戏的缓存文件夹,比如Jewellust。23、sogou:搜狗拼音输入法的随机缓存文件夹,可以删除。24、SpeedSoftware:RE文件管理器的缓存文件夹。25、TalkingFriends:talkingtom(会说话的tom猫)录制的视频文件所保存的目录。26、Tencent:腾讯软件的缓存目录,比如QQ。(与上面的.QQ文件夹并不相同)27、TitaniumBackup:钛备份备份的程序所保存的目录。28、TunnyBrowser:感觉是海豚浏览器的缓存目录,但为什么叫这个名字?金枪鱼浏览器。.29、UCDLFiles:UC迅雷下载文件的保存目录。30、UCDownloads:UC浏览器下载文件缓存的保存目录。31、VIE:Vignette(晕影相机)的缓存目录。32、yd_historys:有道词典搜索历史的缓存目录33、yd_speech:有道词典单词发音的缓存目录。34、youmicache:删掉后还会自动生成,悠米广告的缓存目录,广告程序内嵌在其程序中。35、Glu:Glu系列游戏的资料包存放地,如3D猎鹿人,勇猛二兄弟等。36、apadqq-images:QQforpad的缓存目录。37、DunDef:地牢守护者的数据包。38、KuwoMusic:酷我音乐的相关文件夹。39、MxBrowser:遨游的缓存目录。40、Camera360:相机camera360的随机缓存目录,可以定期清除。41、TTPod:天天动听的缓存目录。42、downloaded:刷了MIUI,升级后的ZIP刷机包,保存在downloaded_rom里。43、.estrongs:当你使用了ES文件管理器解压文件,会有这个缓存记录。它反映使用进程,可以删除。44、silentR:用了后台录音软件,自生的音频文件夹,子文件夹phoneCalls,定期管理清除45、3D-compass:这是使用实景指南针软件,生成的景象图片(图像和数字比较详细)文件夹,可以清除。46、PDF:可移植文档格式,Pdf阅读器存储文件夹。47、Zidanyou:是字典的词库文件储存,删除了要重新下载词库。48、Callrecords:采用第三方强制双向录音软件(手机未root),音频文件保存。49、VPlayerPro:是MOBO等视频播放器使用后的记录定期删除。50、BeWeather(Videos):是气象类软件(如黑莓天气.。.等)附加下载音频或动画图标的储存地址,删除了会无图无声显示。51、thumbnails:用第三方播放器观看手持移动类视频媒体时,存放点击暂停、随机截图以及文件储存时产生的内容。52、iQuran(meta2):可兰经浏览文本和音频的储存文件。53、Autodesk:手机系统自带存储器命令生成文件夹:储存图像或编写文稿,可以查看、备份或者删除。54、PixlrOMatic:后期特效处理图片软件Pixlo,储存文件夹,打开可以预览看效果。55、mapbar:图吧导航地图存放文件,有必须主文件和不同地区具体地图,主文件删掉要重下!56、antTTS:是使用了高德导航选择语音种类导航、语种的下载地址,删掉了语音提示会丢失。57、kingsoft:金山词霸专用文件夹下载储存词库、更新拓展文汇(官方发布修正补充)。58、NightVisionCamera:夜间拍照相机相片存放的地址。59、DSA:电子狗专用夹,收录各地区道路探头监控位置信息,会定期更新。已测试配合高德、凯立德提前预警,效果不错。60、apexlauncher:尖端桌面启动器文件夹,位置在andriod/data/,放置桌面设置备份bak文件。
⑵ android okhttp怎么删除缓存
okhttp在3.0之后缓存时间很短,十几秒,只有设置lurcache时才可以长时间缓存,清除缓存可以将lrucache清除
⑶ Android网络实战篇——OkHttp3(Retrofit2)五种缓存模式的实现
网上有许多写或搏OKhttp3缓存的文章,例如:
【Okhttp3结合Retrofit2 实现缓存】 https://www.jianshu.com/p/74d2c10c3eba?from=timeline
【使用衫侍祥Retrofit和Okhttp3实现网络缓存】谈拆 https://www.jianshu.com/p/34f73e571ecb
【okhttp3缓存实践】 http://blog.csdn.net/wuhengde/article/details/54927096
这些文章都很不错,但还是有一些小小的瑕疵,这里我参考他们的文章结合自己的实践简单封装了Okhttp3的五种缓存方式供大家参考,如有错误还请不吝赐教。
主要知识点:
public class OkHttpUtil {
}
后记:如有不同见解或疑惑,欢迎留言,如果觉得不错可以来个赞!点个赞!
⑷ OkHttp的使用总结
dependencies{
//...
//OkHttp
implementation'com.squareup.okhttp3:okhttp:3.14.2'
implementation'com.squareup.okio:okio:1.17.4'
}
需要注意OkHttp在3.13.x以上的版本需要在Android 5.0+和java1.8的环境开发。Okio在1.x版本是基于Java实现的,2.x则是Kotlin实现的。
OkHttpClient:客户端对象
Request:访问请求,Post请求中需要包含RequestBody
RequestBody:请求数据,在Post请求中用到
Response:网络请求的响应结果
Interceptor:拦截器,能够监控,重写以及重试(请求的)调用
MediaType:数据类型,用来表明数据是json,image,pdf等一系列格式
client.newCall(request).execute():同步的请求方法。
client.newCall(request).enqueue(Callback callback):异步的请求方法
注意点:Callback是执行在子线程中的,不能在此更新UI操作,okhttp2.2以后才有拦截器的概念。
1.同步get:需要自己写子线程请求
2.异步get
说明:Request.Builder 中默认使用get请求,所以可以不调用get()方法
3.post请求
其中RequestBody可以是JSON,表单,键值对,文件等
表单
基本流程都是先创建一个OkHttpClient对象,然后通过Request.Builder()创建一个Request对象,OkHttpClient对象调用newCall()并传入Request对象就能Call对象。而同步和异步不同的地方在于execute()和enqueue()方法的调用,调用execute()为同步请求并返回Response对象,调用enqueue()方法通过callback的形式返回Response对象。
其中这两个方法最终会调用RealCall总的
()方法,从拦截器链中获取返回结果;拦截器链中,依次通过RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor、CallServerInterceptor,与服务器建立连接后,获取返回数据,在经过上述拦截器依次处理后,最后将结果返回给调用方。
拦截器的作用:可以在应用拿到response之前,先获得response,对其某些数据进行监控,在有必要的情况下,对response中某些内容比如response的header,body,response内的request的header,body进行更改。
重拾及重定向拦截器RetryAndFollowUpInterceptor: 负责请求的重试和重定向
桥接拦截器BridgeInterceptor:给请求添加对用的header信息,处理响应结果的header信息
缓存拦截器CacheInterceptor:根据当前获取的状态选择网络请求、读取缓存、更新缓存。
连接拦截器ConnectInterceptor:建立http连接。
读写拦截器CallServerInterceptor:通过连接好的通道进行数据的交换;
1)ApplicationInterceptor(应用拦截器)
2)NetworkInterceptor(网络拦截器)
应用拦截器作用于okhttpCore和Application之间,网络拦截器作用于network和okhttpCore之间,添加应用拦截器的接口是addInterceptor(),而添加网络拦截器的接口是addNetworkInterceptor();
NetworkInterceptor:记录日志
ApplicationInterceptor:动态添加请求公共参数,检查请求路径权限(如是否登录状态)
说明:在某些特殊情况下,网络拦截器可能被执行多次,但是applicationInterceptor只会被执行一次。
addHeader(String name, String value) :添加header信息
removeHeader(String name):移除header信息
header(String name, String value):重新设置指定name的header信息
headers(Headers headers):移除原有的header信息,将参数headers添加到请求中
⑸ okhttp3怎么设置代理
okhttp3 复用okhttpclient配置
所有HTTP请求的代理设置,超时,缓存设置等都需要在OkHttpClient中设置。如果需要更改一个请求的配置,可以使用OkHttpClient.newBuilder()获取一个builder对象,该builder对象与原来OkHttpClient共享相同的连接池,配置等。
如下示例,拷贝2个'OkHttpClient的配置,然后分别设置不同的超时时间;
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
.build();
try {
// Copy to customize OkHttp for this request.
OkHttpClient = client.newBuilder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Response response = .newCall(request).execute();
System.out.println("Response 1 succeeded: " + response);
} catch (IOException e) {
System.out.println("Response 1 failed: " + e);
}
try {
// Copy to customize OkHttp for this request.
OkHttpClient = client.newBuilder()
.readTimeout(3000, TimeUnit.MILLISECONDS)
.build();
Response response = .newCall(request).execute();
System.out.println("Response 2 succeeded: " + response);
} catch (IOException e) {
System.out.println("Response 2 failed: " + e);
}
}
⑹ 如何用okhttp访问本地url
POST TO A SERVER
Posting a String:
public static final MediaType jsonReq
= MediaType.parse(application/json; charset=utf-8);
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(jsonReq, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
Posting Streaming:
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse(text/x-markdown; charset=utf-8);
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody requestBody = new RequestBody() {
@Override public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8(Numbers
);
sink.writeUtf8(-------
);
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format( * %s = %s
, i, factor(i)));
}
}
private String factor(int n) {
for (int i = 2; i < n; i++) {
int x = n / i;
if (x * i == n) return factor(x) + × + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url()
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException(Unexpected code + response);
System.out.println(response.body().string());
}
Posting a File:
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse(text/x-markdown; charset=utf-8);
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
File file = new File(README.md);
Request request = new Request.Builder()
.url()
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException(Unexpected code + response);
System.out.println(response.body().string());
}
Posting from parameters:
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody formBody = new FormEncodingBuilder()
.add(search, Jurassic Park)
.build();
Request request = new Request.Builder()
.url()
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException(Unexpected code + response);
System.out.println(response.body().string());
}
Posting a multipart request:
private static final String IMGUR_CLIENT_ID = ...;
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse(image/png);
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of(Content-Disposition, form-data; name= itle),
RequestBody.create(null, Square Logo))
.addPart(
Headers.of(Content-Disposition, form-data; name=image),
RequestBody.create(MEDIA_TYPE_PNG, new File(website/static/logo-square.png)))
.build();
Request request = new Request.Builder()
.header(Authorization, Client-ID + IMGUR_CLIENT_ID)
.url()
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException(Unexpected code + response);
System.out.println(response.body().string());
}
Posing Json with Gson
private final OkHttpClient client = new OkHttpClient();
private final Gson gson = new Gson();
public void run() throws Exception {
Request request = new Request.Builder()
.url()
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException(Unexpected code + response);
Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
for (Map.Entry entry : gist.files.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue().content);
}
}
static class Gist {
Map files;
}
static class GistFile {
String content;
}
Response Caching:
为了缓存响应,你需要一个你可以读写的缓存目录,和缓存大小的限制。这个缓存目录应该是私有的,不信任的程序应不能读取缓存内容。
一个缓存目录同时拥有多个缓存访问是错误的。大多数程序只需要调用一次 new OkHttp() ,在第一次调用时配置好缓存,然后其他地方只需要调用这个实例就可以了。否则两个缓存示例互相干扰,破坏响应缓存,而且有可能会导致程序崩溃。
响应缓存使用HTTP头作为配置。你可以在请求头中添加 Cache-Control: max-stale=3600 ,OkHttp缓存会支持。你的服务通过响应头确定响应缓存多长时间,例如使用 Cache-Control: max-age=9600 。
⑺ Okhttp 使用详解
一个最简单的OkHttpClient
一个复杂点的OkHttpClient配置
具体可配置参数见OkHttpClient.Builder类,几点注意事项:
两种拦截器的区别
官方提供的Logging Interceptor
地址: https://github.com/victorfan336/okhttp-logging-interceptor
gradle.build中添加依赖:
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
通过Request.Builder创建请求,默认是Get请求
主要是构建RequestBody,并设置Content-Type消息头洞扰。
1.普通Post请求
比如json请求
2. 使用FormBody传递键值对参数
Content-Type: application/x-www-form-urlencoded
比如:
3. 使用RequestBody传递Json或File对象
4. 使用MultipartBody同时传递键值对参数和File对象
5. 使用MultipartBody提交分块请求
6. 自定义RequestBody实现流的上传
1、同步执行
由于android强制要求网络请纳段旦求在线程中执行,所以无法使用execute
2、异步执行
1. 设置请求头
2. 设置超时
3. 设置缓存
1、对于Get请求,如果请求参数较多,自己拼接Url较为麻烦
比如
拼接结果: http://www..com/user/login/username=zhangsan&password=123456
如果能做一燃裤些封装,直接addParam(key,value)的形式则会简单很多。
2、Callback在子线程中回调,大部分时候,我们都是需要更新UI的,还需自己post到主线程中处理。
3、构建请求步骤比较多
因此,Square提供了针对OkHttp的封装库Retrofit,另外Github上也有很多第三方的封装库,比如OkGo。
⑻ Okhttp解析(五)缓存的处理
大家好,之前我们讲解了Okhttp网络数据请求相关的内容,这一节我们讲讲数据缓存的处理。本节按以下内容讲解Okhttp缓存相关的内容。
缓存的使用场景很多,通过它可以将数据通过一定的规则存储起来,再次请求数据的时候就可以快速从缓存中读取了,缓存有以下优势。
HTTP本身提供了一套缓存相关的机制。这套机制定义了相关的字段和规则,用来客户端和服务端进行缓存相关的协商,如响应的数据是否需要缓存,缓存有效期,缓存是否有效,服务器端给出指示,而客户端则根据服务端的指示做具体的缓存更新和读取缓存工作。http缓存可以分为两类:
强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,有两个字段Expires和Cache-Control用于标明失效规则。
表示过期时间,由服务端返回。那么下次请求数据时,判断这个Expires过期时间是否已经过了,如果还没有到过期时间,则使用缓存,如果过了过期时间,则重新请求服务器的数据。Expires格式如下:
不过因为服务器和客户端的时间并不是同步的,用一个绝对时间作为过期的标记并不是很明智,所以HTTP1.1之后更多的是Cache-Control,它的控制更加灵活。
表示缓存的控制,有服务端返回。它有以下几个取值:
默认情况下是private,也就是不能共享的。Cache-Control格式如下:
对比缓存,表示需要和服务端进行相关信息的对比,由服务器决定是使用缓存还是最新内容,如果服务器判定使用缓存,返回响应吗304,判定使用最新内容,则返回响应码200和最新数据。对比缓存的判定字段有两组:
ETag表示资源的一种标识信息,用于标识某个资源,由服务端返回,优先级更高。格式如下:
然后客户端再次请求时,加入字段If-None-Match,格式如下:
服务端收到请求的该字段时(之前的Etag值),和资源的唯一标识进行对比,如果相同,说明没有改动,则返回状态码304,如果不同,说明资源被改过了,则返回状态码200和整个内容数据。
Last-Modified表示资源的最近修改时间,由服务端返回,优先级更低。格式如下:
Last-Modified
由服务器返回,表示响应的数据最近修改的时间。
If-Modified-Since
由客户端请求,表示询问服务器这个时间是不是上次修改的时间。如果服务端该资源的修改时间小于等于If-Modified-Since指定的时间,说明资源没有改动,返回响应状态码304,可以使用缓存。如果服务端该资源的修改时间大于If-Modified-Since指定的时间,说明资源又有改动了,则返回响应状态码200和最新数据给客户端,客户端使用响应返回的最新数据。
Last-Modified字段的值(服务端返回的资源上次修改时间),常常被用于客户端下次请求时的If-Modified-Since字段中。
HTTP的缓存规则是优先考虑强制缓存,然后考虑对比缓存。
Okhttp缓存相关的类有如下:
要开启使用Okhttp的缓存其实很简单,只需要给OkHttpClient对象设置一个Cache对象即可,创建一个Cache时指定缓存保存的目录和缓存最大的大小即可。
那么下面我们来看看Okhttp缓存执行的大概流程
Okhttp的缓存流程分为读取缓存和存储缓存两个过程,我们分别分析。
读取使用缓存的流程从HttpEngine的sendRequest发送请求开始。
接下来我们分析
从Cache的get方法开始。它按以下步骤进行。
如果存在缓存的话,在指定的缓存目录中,会有两个文件“****.0”和“****.1”,分别存储某个请求缓存的响应头和响应体信息。(“****”是url的md5加密值)对应的ENTRY_METADATA响应头和ENTRY_BODY响应体。缓存的读取其实是由DiskLruCache来读取的,DiskLruCache是支持Lru(最近最少访问)规则的用于磁盘存储的类,对应LruCache内存存储。它在存储的内容超过指定值之后,就会根据最近最少访问的规则,把最近最少访问的数据移除,以达到总大小不超过限制的目的。
接下来我们分析CacheStrategy缓存策略是怎么判定的。
直接看CacheStrategy的get方法。缓存策略是由请求和缓存响应共同决定的。
接来下我们看看CacheControl类里有些什么。
可以发现,它就是用于描述响应的缓存控制信息。
然后我们再看看Okhttp存储缓存是怎么进行的。
存储缓存的流程从HttpEngine的readResponse发送请求开始的。
可以看到这里先通过maybeCache写入了响应头信息,再通过cacheWritingResponse写入了响应体信息。我们再进去看Cache的put方法实现。
我们继续看Cache的writeTo方法,可以看到是写入一些响应头信息。
到这里Okhttp缓存的读取和存储流程我们就清楚了。可以说,缓存的使用策略基本都是按照HTTP的缓存定义来实现的,所以对HTTP缓存相关字段的理解是很重要的。然后关于DiskLruCache是如何管理缓存文件的,这个其实也很好理解,首先的原则就是按照LRU这种最近最少使用删除的原则,当总的大小超过限定大小后,删除最近最少使用的缓存文件,它的LRU算法是使用LinkedHashMap进行维护的,这样来保证,保留的缓存文件都是更常使用的。具体实现大家可以分析DiskLruCache和LinkedHashMap的实现原理。
⑼ 重识OkHttp——更深入了解如何使用
OkHttp作为square公司出品的一个网络请求框架,应该算是目前Android端最火爆的网络框架了。我公司目前的项目中采用的都是Rxjava结合Retrofit进行网络请求的处理,对于底层真正实现网络请求的OkHttp关注的不是很多。最近探究了一下OkHttp的源码,对OkHttp的使用有了一些新的认识,在此做一下总结。
OkHttp作为当前Android端最火热的网络请求框架,必然有很多的优点。
对于客户端来讲,我们关注的就是把正确的请求发送到服务端并拿到结果来进行处理。在OkHttp中,我认为可以分为3个部分:
OkHttp中通过建造者模式来构建OkHttpClient、Request和Response。对于客户端来讲,我们不需要过多关注Response是如何构建的,因为这个是OkHttp对响应结果进行了封装处理。我们只关注请求Request和客户端OkHttpClient如何构建即可。
Request采用建造者模式来配置url,请求方法method、header、tag和cacheControl。
OkHttp采用POST方法向服务器发送一个请求体,在OkHttp中这个请求体是RequestBody。这个请求体可以是:
RequestBody有几个静态方法用于创建不同类型的请求体:
最终都是相当于重写了RequestBody的两个抽象方法来写入流,如果传递流类型的参数,只要重写这两个抽象方法即可。
例如,我们提交一个String:
提交File:
提交流:
对于提交表单和分块请求,OkHttp提供了两个RequestBody的子类, FormBody 和 MultipartBody
FormBody也是采用建造者模式, 这个很简单,添加key-value形式的键值对即可。
添加键值对有两个方法:
例如:
MultipartBody也是采用建造者模式,MultipartBody.Builder可以构建兼容Html文件上传表单的复杂请求体。每一部分的多块请求体都是它自身的请求体,并且可以定义它自己的请求头。如果存在的话,这些请求头用来描述这部分的请求体。例如Content-Disposition、Content-Length 和 Content-Type如果可用就会被自动添加到头。
MIME类型有:
有几个主要的方法:
例如提交一个图片文件:
OkHttpClient采用建造者模式,通过Builder可以配置连接超时时间、读写时间,是否缓存、是否重连,还可以设置各种拦截器interceptor等。
建议在一个App中,OkHttpClient保持一个实例。一个OkHttpClient支持一定数量的并发,请求同一个主机最大并发是5,所有的并发最大是64。这个与OkHttp中的调度器Dispatcher有关,可以设置并发数。本文不对Dispatcher进行讨论。
一个例子:
OkHttpClient支持单独配置,例如原来设置不同的请求时间,可以通过OkHttpClient的newBuilder()方法来重新构造一个OkHttpClient。例如:
上面已经讲了如何创建Request和OkHttpClient,剩下的就是发送请求并得到服务器的响应了。OkHttp发送请求可分为同步和异步。OkHttpClient首先通过Request构建一个Call,通过这个Call去执行同步或者异步请求。
同步方式,调用Call的execute()方法,返回Response,会阻塞当前线程:
异步方式,调用Call的enqueue(CallBack callBack)方法,会在另一个线程中返回结果。
为了缓存响应,需要一个可读写并且设置大小Size的缓存目录。缓存目录需要私有,其它不信任的应用不能访问这个文件。
如果同时有多个缓存访问同一个缓存目录会报错。所以最好只在App中初始化一次OkHttpClient,给这个实例配置缓存,在整个App生命周期内都用这一个缓存。否则几个缓存会相互影响,导致缓存出错,引起程序崩溃。
响应缓存采用Http头来配置,你可以添加这样的请求头 Cache-Control: max-stale=3600 。 max-age 指的是客户端可以接收生存期不大于指定时间(以 秒 为单位)的响应。
为了防止响应使用缓存,可以用 CacheControl.FORCE_NETWORK 。为了防止使用网络,采用 CacheControl.FORCE_CACHE 。
调用Call.cancel()方法可以立即取消一个网络请求。如果当前线程正在写request或者读response会报IO异常。如果不再需要网络请求,采用这种方法是比较方便的。例如在App中返回了上一页。无论是同步还是异步的请求都可以被取消。
可以通过Response的code来判断请求是否成功,如果服务器返回的有数据,可以通过Response的body得到一个ResponseBody读取。
如果采用ResponseBody的string()方法会一次性把数据读取到内存中,如果数据超过1MB可能会报内存溢出,所以对于超过1MB的数据,建议采用流的方式去读取,如ResponseBody的byteStream()方法。
需要说明的是:
OkHttp中的很多类都用到了建造者模式,可以根据需要灵活配置。采用建造者模式的有:
如果单独使用OkHttp进行网络请求,通常需要开发者自己再封装一下,如果不想重复造轮子,Github上面的有一些优秀开源库可以拿来使用(本文只列出star较多的几个):
OkHttp官方Wiki文档