现在的网络应用越来越平常化,几乎每个应用都比不可少的要与网络接轨。我们在开发的时候,网络请求写的也算是家常便饭了。现在市面上的网络请求框架很多,举几个例子比如:Volley, AsyncHttpClient,
xUtils,okHttp,等等,很多。但是在写了这么多的应用之后发现,一直研究别人的代码如何去用,还不如自己写一个。什么都在自己掌控之内,腰不酸腿也不疼了。经过种种思量之后,打算写自己的网络请求框架。既然决定要写,那就要把之前遇到的问题全部解决,这些问题包括:
1.缓存控制,多样性控制,什么意思呢?比如请求失败后是否使用缓存,请求超时了是否使用缓存等。
2.Cookie的问题。
3.请求的取消
4.请求的并发
5.重复请求的问题
6.请求的优先级
7.请求失败重试机制
有了目标,那么我们就针对这些问题一个一个来解决。
第一条:
缓存的控制,缓存我设计了两级缓存,即内存缓存LruCache,与磁盘缓存DiskLruCache,在写的过程中发现缓存需要解决的问题是对象的存储问题,我使用了一个CacheData的缓存对象,内部封装了数据源,缓存过期等相关控制,这一个对象就相当于一个请求的缓存数据,那么我们需要对这个对象进行存储,内存存储还好,因为LruCache本身就是可缓存对象的,而磁盘缓存DiskLruCache 存储起来就需要做些处理了,把一个对象存储到磁盘,经过搜索相关资料,只能使用序列化的方式,让CacheData对象实现序列化接口,存储的时候我们就可以使用“ObjectOutputStream”来存储对象。
下面是我写好的一个存储对象函数:
/**
* set the data to disk cache
* @param originalKey
*/
public void setDataToDiskCache(String originalKey,ValueType value){
try {
String key = hashKeyForDisk(originalKey);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
ObjectOutputStream oos=new ObjectOutputStream(outputStream);
if (value!=null) {
oos.writeObject(value);
}
/*if (oos!=null) {
oos.close();
}*/
if (getDataFromDiskCache(originalKey)==null) {
editor.commit();
} else {
editor.abort();
}
}
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
上面的ValueType是一个泛型类。
这样缓存存储问题先搞定了。接下来是设计缓存的控制,这个部分比较绕。我的设计如下:
cacheConfig.setShouldCache(true); // 是否允许缓存 ①为true 时,请求完成后更新缓存,②为false 时,直接使用请求数据,请求完成后不更新缓存
cacheConfig.setUseCacheDataAnyway(false); //是否总是使用缓存数据 ①为true 时 直接使用缓存数据,不管缓存有没有过期,并在请求完成后更新缓存。如果缓存不存在,则进行网络请求,请求完成后使用最新数据并更新缓存
cacheConfig.setUseCacheDataWhenRequestFailed(true); //当网络请求失败的时候是否使用缓存数据①为 true 时 在请求失败的时候使用缓存,②为 false 时,请求失败时不使用缓存
cacheConfig.setUseCacheDataWhenTimeout(true); //当网络请求超时后直接使用缓存数据,后面在网络请求完成后更新缓存
cacheConfig.setUseCacheDataWhenUnexpired(true); //当缓存存在并未过期的时候是否使用缓存数据①为 true 时 当缓存数据存在并且未过期,使用缓存数据,如果缓存不存在或者过期,则进行网络请求,请求完成后使用最新数据,且如果允许缓存,更新缓存②为false 时 直接进行网络请求,请求完成后使用最新数据,且如果允许缓存,更新缓存
缓存控制问题也搞定了。
第二条:
Cookie的问题,其实这个问题也不算个问题,为什么这么说呢?现在Android中的网络请求有两种方式,一种是Android为我们提供的HttpUrlConnection,另一种就是Apache的HttpClient,无论哪种请求方式,我们获得Cookie,只需要从这两个对象中便可直接拿到,既然这么简单,又为什么单独拿出来说一下,因为之前使用过一次别人的框架,项目中需要获取SessionId,悲催的发现这个框架没有获得Cookie的方法,也没有获取HttpUrlConnection或者HttpClient对象的接口,问了作者,他说暂时没办法,怎么搞勒,只能自己改源码咯,又要花一番功夫去研究下他的代码,好歹最后搞定了这个问题。
第三条:请求的取消
这个问题,说简单不简单,说难其实也不难,后面会说到这个问题
第四条:
请求的并发,这个算比较重要的问题,很容易忽略,在之前的项目中,使用了一个网络请求对象,同时进行两请求,结果发现其中一个请求始终无法获取返回值,找了很久终于发现了这个问题,作者请求框架中使用了一个线程进行网络请求,所以没办法并发。ok,知道了问题,我们的解决方法也出来了,”多线程“并发即可
第五条:
重复请求的问题,模拟一个场景:在一个电商的项目中,用户进入一个商品详情页面,退出进汝,再退出再进入,反复多次。这样同一个请求就请求了多次,每次都会连接网络。那你会说,不是有缓存了吗,后面再请求不就会使用缓存了吗!?当前面的请求完成后确实会达到这个效果,但是在实际中,可能网速慢等多种情况,前面的请求还没完成呢,这时候又发起了第二个第三个请求,这样就连接了三次网络,造成流量的浪费,电量等资源的损耗。所以这个问题需要我们进行严格的控制,怎么控制,看后面
第六条:
请求的优先级,关于优先级,与上面一样,后面一起说
第七条:
重试机制,这个我们可以定义一个策略,并且这个这个策略可以自定义
这七个问题,其中”第三条“”第五条“”第六条“,请求的取消,请求重复问题,请求的优先级问题,在Volley中已经有了很好的实现,而我们可以参考volley的做法,原理是使用队列
把请求加入队列中,当我们需要取消请求的时候,只需要把它从队列中移除即可
而请求重复的问题,也可以得到解决,当发现队列中有相同的请求时,把后面的请求通通加入一个第三方队列,当请求完成时,释放第三方队列,释放后的请求就可以使用前面的请求的缓存数据了
同样的,优先级问题也可以通过队列解决,在队列queue中,有很多不同的队列类,其中PriorityBlockingQueue就是一个可以进行自定义排序的队列,我们可以从这方面着手
这样所有的问题就得到了解决。下面就是编码了,代码已经完成了,90%,目前未实现的功能有重试机制,这个后面会陆续加上,下面放一张,画的简单的流程草图
转载时请注明出处及相应链接,本文永久地址:https://blog.yayuanzi.com/11378.html
微信打赏
支付宝打赏
感谢您对作者wangbin的打赏,我们会更加努力! 如果您想成为作者,请点我