OkHttp的使用简介及封装,实现更简洁的调用

来源:互联网 发布:看足球赛的软件 编辑:程序博客网 时间:2024/04/28 19:43


最近将项目使用的网络请求库换成了OkHttp,体验感觉上升了好几个档次啊,-。-,之前项目是好几年前的,封装了原生的httpClient,没有实现异步请求,每次都要自己开个线程,然后再实现退出的时候把线程关了,还要实现本地缓存,啊,听起来好麻烦有木有,然后我终于受不了了,自己封装了下OkHttp(。。。其实这个是好久前写的代码,一直没机会实际运用,刚好可以当小白鼠)。。。。不废话了

1.首先,OkHttp本身是有缓存这个东西的,只是如果你不去设置,是不起作用的 


client.setCache(new Cache(context.getCacheDir(),maxCacheSize));
.
 
设置缓存目录和缓存大小,OkHttp内部是使用LRU来管理缓存的 
2.当然,设置了缓存和目录还是不够的,http请求总该有个过期时间吧,缓存是由HTTP消息头中的”Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。 

伦理片 http://www.dotdy.com/

下面是作用:

  • public 所有内容都将被缓存
  • private 内容只缓存到私有缓存中
  • no-cache 所有内容都不会被缓存
  • no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中
  • must-revalidation/proxy-revalidation 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证
  • max-age=xxx (xxx is numeric) 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

一般来说我们用到的是no-cache和max-age比较多,既然我们要实现缓存,那么自然就要在我们的每一条的请求头里面添加这个属性,OkHttp提供了Interceptor 拦截器这个东西,做过web应该明白,就是在你一条http请求要发送之前,拦截下来,做一些处理然后再继续发送,因此,我们就可以添加一个拦截器,在请求前把Cache-control:max-age=36000添加到请求头里去。


Prettyprint代码  收藏代码
  1. <code class="hljs java has-numbering">  
  2. Interceptor cacheInterceptor = <span class="hljs-keyword">new</span> Interceptor() {  
  3.             <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> Response <span class="hljs-title">intercept</span>(Chain chain) <span class="hljs-keyword">throws</span> IOException {  
  4.                 Response originalResponse = chain.proceed(chain.request());  
  5.                 <span class="hljs-keyword">return</span> originalResponse.newBuilder()  
  6.                         .removeHeader(<span class="hljs-string">"Pragma"</span>)<span class="hljs-comment">//Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同。为了确保缓存生效</span>  
  7.                         .header(<span class="hljs-string">"Cache-Control"</span>, String.format(<span class="hljs-string">"max-age=%d"</span>, maxCacheAge))<span class="hljs-comment">//添加缓存请求头</span>  
  8.                         .build();  
  9.             }  
  10.         };  
  11.   
  12. </code>  

 

 

3.嗯,差不多到这一步就已经快完成了,剩下的就是调用OkHttp的方法了。

Prettyprint代码  收藏代码
  1. <code class="hljs avrasm has-numbering">.  
  2. Request<span class="hljs-preprocessor">.Builder</span> requestBuilder = new Request<span class="hljs-preprocessor">.Builder</span>()<span class="hljs-preprocessor">.url</span>(url)<span class="hljs-preprocessor">.cacheControl</span>(cacheControl)<span class="hljs-comment">;</span>  
  3. .</code>  

一个OkHttp的请求大致是这样子的,url是必须的,然后如果我们要实现缓存,cacheControl也是必须的,OkHttp提供了CacheControl这个类,里面FORCE_CACHE 和FORCE_NETWORK分别表示只从缓存获取数据和只通过网络请求获取数据,有了前面的两步设置,这时我们是可以通过设置FORCE_CACHE 来从缓存获取数据而不通过网络获取服务器的数据的(前提是你本地要有缓存,也就是必须先通过网络请求获取到一次数据才能获取到缓存),代码没什么,就不贴了。


嗯,我们的网络请求实现本地缓存已经实现,当你网络请求失败的时候又不希望展示给用户的是一片空白,那你就可以调用本地之前的缓存了!!你别告诉我这样你就满足了,这每次都要判断是不是请求失败了,要不要请求缓存,这想想都蛋疼啊!!!

所以我对OkHttp进行封装,实现了只查询缓存,网络请求失败自动查询本地缓存等功能 


支持4种不同的查询方式

*ONLY_NETWORK 只查询网络数据

*ONLY_CACHED 只查询本地缓存

*CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据

*NETWORK_ELSE_CACHED 先查询网络数据,如果没有,再查询本地缓存

支持get和post请求,默认查询方式为NETWORK_ELSE_CACHED,可通过Builder来指定默认查询方式

===================我是分隔符================= 
先贴代码

Prettyprint代码  收藏代码
  1. <code class="hljs sql has-numbering"> //实现一个最基本的请求方法  
  2. private <span class="hljs-operator"><span class="hljs-keyword">Call</span> request(Request request, Callback callback){  
  3.         <span class="hljs-keyword">if</span>(DEBUG){  
  4.             Log.d(<span class="hljs-string">"OKHttp"</span>,request.toString());</span>  
  5.         }  
  6.         <span class="hljs-operator"><span class="hljs-keyword">Call</span> <span class="hljs-keyword">call</span> = client.newCall(request);</span>  
  7.         <span class="hljs-operator"><span class="hljs-keyword">call</span>.enqueue(callback);</span>  
  8.         return <span class="hljs-operator"><span class="hljs-keyword">call</span>;</span>  
  9.     }  
  10. </code>  
Prettyprint代码  收藏代码
  1. <code class="hljs java has-numbering"><span class="hljs-comment">//实现自己的回调,添加了onStart和onFinish方法</span>  
  2. <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Callback</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">com</span>.<span class="hljs-title">squareup</span>.<span class="hljs-title">okhttp</span>.<span class="hljs-title">Callback</span> {</span>  
  3.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>(){  
  4.   
  5.     }  
  6.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>(){  
  7.   
  8.     }  
  9.   
  10.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFailure</span>(Request request, IOException e);  
  11.   
  12.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Response response) <span class="hljs-keyword">throws</span> IOException;  
  13. }</code>  
Prettyprint代码  收藏代码
  1. <code class="hljs java has-numbering"><span class="hljs-comment">//定义一个公用的方法,实现最基本的封装,无论是post还是get都适用</span>  
  2. <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">request</span>(String url, String method, RequestBody requestBody, <span class="hljs-keyword">final</span> CacheControl cacheControl, Headers headers,Object tag ,<span class="hljs-keyword">final</span> Callback callback){  
  3.         <span class="hljs-keyword">final</span> Request.Builder requestBuilder = <span class="hljs-keyword">new</span> Request.Builder().url(url).cacheControl(cacheControl);  
  4.         <span class="hljs-keyword">if</span>(headers!=<span class="hljs-keyword">null</span>){  
  5.             requestBuilder.headers(headers);  
  6.         }  
  7.         requestBuilder.method(method,requestBody);<span class="hljs-comment">//如果是get请求,这里requestBody就应该传个null</span>  
  8.         requestBuilder.tag(tag==<span class="hljs-keyword">null</span>?url:tag);<span class="hljs-comment">//OkHttp的tag是对请求的标志,可以通过tag来获取到请求和取消请求,这里如果你不传,就将当前url设置为tag</span>  
  9.   
  10.         <span class="hljs-keyword">final</span> Request request = requestBuilder.build();  
  11.         request(request,<span class="hljs-keyword">new</span> Callback() {<span class="hljs-comment">//这里是回调</span>  
  12.   
  13.             <span class="hljs-annotation">@Override</span>  
  14.             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() {  
  15.                 <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  16.                     callback.onStart();  
  17.                 }  
  18.             }  
  19.   
  20.             <span class="hljs-annotation">@Override</span>  
  21.             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>() {  
  22.                 <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  23.                     callback.onFinish();  
  24.                 }  
  25.             }  
  26.   
  27.             <span class="hljs-annotation">@Override</span>  
  28.             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFailure</span>(Request request, IOException e) {  
  29.                 <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  30.                     callback.onFailure(request,e);  
  31.                     callback.onFinish();  
  32.                 }  
  33.             }  
  34.   
  35.             <span class="hljs-annotation">@Override</span>  
  36.             <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Response response) <span class="hljs-keyword">throws</span> IOException {  
  37.                 <span class="hljs-keyword">if</span>(response.code()==<span class="hljs-number">504</span>){<span class="hljs-comment">//OkHttp如果缓存请求不到是会报504的</span>  
  38.                     <span class="hljs-keyword">if</span>(CacheControl.FORCE_CACHE == cacheControl){  
  39.                         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  40.                             callback.onFailure(request,<span class="hljs-keyword">new</span> IOException(<span class="hljs-string">"cached not found"</span>));  
  41.                             callback.onFinish();  
  42.                         }  
  43.                         <span class="hljs-keyword">return</span>;  
  44.                     }  
  45.                 }  
  46.                 <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  47.                     callback.onResponse(response);  
  48.                     callback.onFinish();  
  49.                 }  
  50.             }  
  51.         });  
  52.     }  
  53. </code>  
Prettyprint代码  收藏代码
  1. <code class="hljs oxygene has-numbering"><span class="hljs-comment">//实现只请求网络和只请求缓存的方法</span>  
  2.  <span class="hljs-keyword">public</span> void requestFromNetwork(<span class="hljs-keyword">final</span> String url,String <span class="hljs-function"><span class="hljs-keyword">method</span>,<span class="hljs-title">RequestBody</span> <span class="hljs-title">requestBody</span>, <span class="hljs-title">Headers</span> <span class="hljs-title">headers</span>,<span class="hljs-title">Object</span> <span class="hljs-title">tag</span>,<span class="hljs-title">final</span> <span class="hljs-title">Callback</span> <span class="hljs-title">callback</span>)<span class="hljs-comment">{  
  3.         request(url,method,requestBody,CacheControl.FORCE_NETWORK,headers,tag,callback);  
  4.     }</span>  
  5.   
  6.     <span class="hljs-title">public</span> <span class="hljs-title">void</span> <span class="hljs-title">requestFromCached</span><span class="hljs-params">(String url,String <span class="hljs-keyword">method</span>,RequestBody requestBody,Headers headers ,Object tag,<span class="hljs-keyword">final</span> Callback callback)</span><span class="hljs-comment">{  
  7.         request(url,method,requestBody,CacheControl.FORCE_CACHE,headers,tag,callback);  
  8.     }</span></span></code>  


重点来了!! 
定义了4种请求类型 
*ONLY_NETWORK 只查询网络数据

*ONLY_CACHED 只查询本地缓存


*CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据

*NETWORK_ELSE_CACHED 先查询网络数据,如果没有,再查询本地缓存

前两种都没什么好说的,直接调用写好的两个方法requestFromNetwork和requestFromCached就行了 
后面两种: 

 影音先锋电影 http://www.iskdy.com/
1.CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据,我们就需要自己再传一个Callback c2回调了,当回调执行成功的时候,我们直接就调用方法的回调的onResponse就行,其余情况我们就需要查询网络的数据,到了这一步,说明本地没有缓存了,所以直接调用requestFromNetwork就行

Prettyprint代码  收藏代码
  1. <code class="hljs java has-numbering"> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">request</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> CacheType cacheType, <span class="hljs-keyword">final</span> String method, <span class="hljs-keyword">final</span> RequestBody requestBody, <span class="hljs-keyword">final</span> Headers headers, <span class="hljs-keyword">final</span> Object tag , <span class="hljs-keyword">final</span> Callback callback){  
  2.         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>)callback.onStart();  
  3.         <span class="hljs-keyword">switch</span> (cacheType){  
  4.             <span class="hljs-keyword">case</span> ONLY_NETWORK:<span class="hljs-comment">//只查询网络数据</span>  
  5.                 requestFromNetwork(url,method,requestBody,headers,tag,callback);  
  6.                 <span class="hljs-keyword">break</span>;  
  7.             <span class="hljs-keyword">case</span> ONLY_CACHED:<span class="hljs-comment">//只查询本地缓存</span>  
  8.                 requestFromCached(url,method,requestBody,headers,tag,callback);  
  9.                 <span class="hljs-keyword">break</span>;  
  10.             <span class="hljs-keyword">case</span> CACHED_ELSE_NETWORK:  
  11.                 requestFromCached(url,method,requestBody,headers,tag, <span class="hljs-keyword">new</span> Callback() {  
  12.                     <span class="hljs-annotation">@Override</span>  
  13.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() {  
  14.                         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  15.                             callback.onStart();  
  16.                         }  
  17.                     }  
  18.   
  19.                     <span class="hljs-annotation">@Override</span>  
  20.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>() {  
  21.                         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  22.                             callback.onFinish();  
  23.                         }  
  24.                     }  
  25.   
  26.                     <span class="hljs-annotation">@Override</span>  
  27.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFailure</span>(Request request, IOException e) {  
  28.                         requestFromNetwork(url,method,requestBody,headers,tag,callback);  
  29.                     }  
  30.   
  31.                     <span class="hljs-annotation">@Override</span>  
  32.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Response response) <span class="hljs-keyword">throws</span> IOException {  
  33.                         <span class="hljs-keyword">if</span>(response.code()==<span class="hljs-number">200</span>){<span class="hljs-comment">//response.isSuccessful()OkHttp是有这个方法判断请求是否成功的,但判断的方法是根据状态码是否是20开头(200201202203等,具体区别就不在这里描述了,有兴趣的百度)来判断的,但只有200返回的数据才是我们想要的</span>  
  34.                             <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  35.                                 callback.onResponse(response);  
  36.                                 callback.onFinish();  
  37.                             }  
  38.                         }<span class="hljs-keyword">else</span>{  
  39.                             requestFromNetwork(url,method,requestBody,headers,tag,callback);  
  40.                         }  
  41.                     }  
  42.                 });  
  43.                 <span class="hljs-keyword">break</span>;  
  44.             <span class="hljs-keyword">case</span> NETWORK_ELSE_CACHED:  
  45.                 requestFromNetwork(url,method,requestBody,headers,tag, <span class="hljs-keyword">new</span> Callback() {  
  46.                     <span class="hljs-annotation">@Override</span>  
  47.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() {  
  48.                         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  49.                             callback.onStart();  
  50.                         }  
  51.                     }  
  52.   
  53.                     <span class="hljs-annotation">@Override</span>  
  54.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>() {  
  55.                         <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  56.                             callback.onFinish();  
  57.                         }  
  58.                     }  
  59.   
  60.                     <span class="hljs-annotation">@Override</span>  
  61.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFailure</span>(Request request, IOException e) {  
  62.                         requestFromCached(url,method,requestBody,headers,tag,callback);  
  63.                     }  
  64.   
  65.                     <span class="hljs-annotation">@Override</span>  
  66.                     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Response response) <span class="hljs-keyword">throws</span> IOException {  
  67.                         <span class="hljs-keyword">if</span>(response.code()==<span class="hljs-number">200</span>){  
  68.                             <span class="hljs-keyword">if</span>(callback!=<span class="hljs-keyword">null</span>){  
  69.                                 callback.onResponse(response);  
  70.                                 callback.onFinish();  
  71.                             }  
  72.                         }<span class="hljs-keyword">else</span>{  
  73.                             requestFromCached(url,method,requestBody,headers,tag,callback);  
  74.                         }  
  75.                     }  
  76.                 });  
  77.                 <span class="hljs-keyword">break</span>;  
  78.         }  
  79.     }</code>  
  • 1

2.NETWORK_ELSE_CACHED 这个和CACHED_ELSE_NETWORK 实现原理是一样的,就略过。

。。。。。写得好累 



!!!你以为这样就完了?还要有json解析啊,这年头,还用自带的json解析有点low 
(。。。。。之前我是用自带的) 


目前json解析的有fastJson、jackJson(这个包比较大,不怎么推荐)、Gson,我这里就用Gson了 
首先,再添加一个回调的类

Prettyprint代码  收藏代码
  1. <code class="hljs cs has-numbering">  
  2. <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> JsonCallback<T> {  
  3.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFailure</span>(Request request, Exception e);  
  4.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(T <span class="hljs-keyword">object</span>) throws IOException;  
  5.   
  6.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>(){  
  7.   
  8.     }  
  9.     <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>(){  
  10.   
  11.     }  
  12.   
  13. <span class="hljs-comment">//这个才是重点,获取Json的类型,因为数据可能集合也可能是Object</span>  
  14.     Type getType(){  
  15.         Type type = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[<span class="hljs-number">0</span>];  
  16.         <span class="hljs-keyword">if</span>(type instanceof Class){  
  17.             <span class="hljs-keyword">return</span> type;<span class="hljs-comment">//如果是Object直接返回</span>  
  18.         }<span class="hljs-keyword">else</span>{  
  19.             <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> TypeToken<T>(){}.getType();<span class="hljs-comment">//如果是集合,获取集合的类型map或list</span>  
  20.         }  
  21.     }  
  22. }  
  23. </code>  

 

 

接下来就是对返回的数据进行解析了

Prettyprint代码  收藏代码
  1. <code class="hljs java has-numbering"><span class="hljs-comment">//这里只贴部分关键代码</span>  
  2.  <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">request</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> CacheType cacheType, <span class="hljs-keyword">final</span> String method, <span class="hljs-keyword">final</span> RequestBody requestBody, <span class="hljs-keyword">final</span> Headers headers,Object tag,<span class="hljs-keyword">final</span> JsonCallback callback)  
  3.   
  4. //在onResponse进行解析,具体看文章结尾源码  
  5. @Override  
  6. <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onResponse</span>(Response response) <span class="hljs-keyword">throws</span> IOException {  
  7.      <span class="hljs-keyword">if</span>(response.isSuccessful() && callback!=<span class="hljs-keyword">null</span>){  
  8.          String jsonString = response.body().string();;  
  9.          <span class="hljs-keyword">if</span>(!TextUtils.isEmpty(jsonString)){  
  10.              Object result = <span class="hljs-keyword">null</span>;  
  11.              <span class="hljs-keyword">try</span> {  
  12.                  result =  gson.fromJson(jsonString,callback.getType());<span class="hljs-comment">//直接调用Gson解析</span>  
  13.                  callback.onResponse(result);  
  14.                  callback.onFinish();  
  15.              } <span class="hljs-keyword">catch</span> (JsonSyntaxException e) {  
  16.                  callback.onFailure(<span class="hljs-keyword">null</span>,<span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"json string parse error :"</span>+e.toString()));  
  17.                  callback.onFinish();  
  18.                  e.printStackTrace();  
  19.              }  
  20.   
  21.          }<span class="hljs-keyword">else</span>{  
  22.              callback.onFailure(<span class="hljs-keyword">null</span>,<span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"json string may be null"</span>));  
  23.              callback.onFinish();  
  24.          }  
  25.      }  
  26.  }</code>  

嗯,写到这里终于完了!!!!下篇写OkHttp的文件下载 
源码戳下面链接,几个点start给个赞啊,写了好多重载函数很累的!!! 

0 0