教你写Android网络框架之请求配置与Response缓存
前言
在教你写Android网络框架的前三篇文章中,我们从基本结构到代码实现,剖析了一个简单的网络框架应该是怎样运作的,以及在面对各式各样的需求时应该如何对代码做出处理,在深入了解网络框架的同时学习到一些简单的面向对象设计原则。正如第一篇博文所说,SimpleNet框架参照的是Volley实现,甚至有一些类名也是一样的。我们的目标并不是要重新发明轮子,而是以学习轮子制作的过程来达到提升自我的目的。SimpleNet只是一个简单的网络框架实现,没有经过严格的测试以及市场检验,不建议大家在项目中使用,当然如果你觉得没有什么问题,在经过测试的情况下也可以运用在自己的项目中。
请求配置与https
在执行http请求时,我们经常需要对http请求进行配置,例如超时配置和https配置等。SimpleNet在这里只做出了简单的配置,如有更多的需求则请自行实现。由于HttpClient和HttpURLConnection所属的类族是不一样的,他们对于Https的配置并没有一个公共的类型,因此这里没有进行抽象,而是针对两个HttpClient和HttpURLConnection创建来两个配置类,其中HttpClientConfig是HttpClientStack的配置类,而HttpUrlConnConfig则是HttpUrlConnStack的配置类。
例如配置https时,httpClient的SSLSocketFactory所在的包为org.apache.http.conn.ssl.SSLSocketFactory;而HttpURLConnection的SSLSocketFactory所在的包却是javax.net.ssl.SSLSocketFactory。这是apache和Android团队的不同实现,因此不好做出抽象层,我们这里使用两个配置类来进行配置。
使用HttpClient时配置https请参考httpclient中使用HTTPS的方法,使用HttpUrlConnStack执行https请求时配置https请参考Android网络编程——https 不验证证书方式(信任所有证书)。
例如,在低于api 9时,用户可以通过HttpClientConfig来配置SSLSocketFactory,然后在执行请求时会获取配置类的SSLSocketFactory来设置HttpClient。
package org.simple.net.config; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; /** * 这是针对于使用HttpUrlStack执行请求时为https请求设置的SSLSocketFactory和HostnameVerifier的配置类,参考 * http://blog.csdn.net/xyz_lmn/article/details/8027334,http://www.cnblogs.com/ * vus520/archive/2012/09/07/2674725.html, * * @author mrsimple */ public class HttpUrlConnConfig extends HttpConfig { private static HttpUrlConnConfig sConfig = new HttpUrlConnConfig(); private SSLSocketFactory mSslSocketFactory = null; private HostnameVerifier mHostnameVerifier = null; private HttpUrlConnConfig() { } public static HttpUrlConnConfig getConfig() { return sConfig; } /** * 配置https请求的SSLSocketFactory与HostnameVerifier * * @param sslSocketFactory * @param hostnameVerifier */ public void setHttpsConfig(SSLSocketFactory sslSocketFactory, HostnameVerifier hostnameVerifier) { mSslSocketFactory = sslSocketFactory; mHostnameVerifier = hostnameVerifier; } public HostnameVerifier getHostnameVerifier() { return mHostnameVerifier; } public SSLSocketFactory getSslSocketFactory() { return mSslSocketFactory; } }
在HttpClientStack中执行请求时,会判断是否是https请求,如果是则需要获取配置类中配置的SSLSocketFactory,代码如下 :
/** * 如果是https请求,则使用用户配置的SSLSocketFactory进行配置. * * @param request */ private void configHttps(Request<?> request) { SSLSocketFactory sslSocketFactory = mConfig.getSocketFactory(); if (request.isHttps() && sslSocketFactory != null) { Scheme sch = new Scheme("https", sslSocketFactory, 443); mHttpClient.getConnectionManager().getSchemeRegistry().register(sch); } }
HttpUrlConnStack的https设置也是类似的,就不给出了。由于没有服务器,对于Https的配置本人并没有经过测试,如有问题请自行调试了。
Response缓存
在某些情况下,数据并不会每次都需要从服务端获取,因此我们添加了Response缓存。这样就可以避免不必要的请求浪费流量,也可以提升用户体验。用户可以通过Request的setShouldCache(boolean shouldCache)方法来设置是否缓存该请求的Response,如果是true那么则缓存,否则不缓存。
在执行请求时,会判断是否缓存该请求的Response,如果是,那么会将该Response缓存到内存中。如果该请求开启了缓存,那么在请求前会判断是否含有缓存,如果有缓存则直接取缓存结果,没有缓存才从服务端获取。如下是NetworkExecutor中执行网络请求的代码。
@Override public void run() { try { while (!isStop) { final Request<?> request = mRequestQueue.take(); if (request.isCanceled()) { Log.d("### ", "### 取消执行了"); continue; } Response response = null; if (isUseCache(request)) { // 从缓存中取 response = mReqCache.get(request.getUrl()); } else { // 从网络上获取数据 response = mHttpStack.performRequest(request); // 如果该请求需要缓存,那么请求成功则缓存到mResponseCache中 if (request.shouldCache() && isSuccess(response)) { mReqCache.put(request.getUrl(), response); } } // 分发请求结果 mResponseDelivery.deliveryResponse(request, response); } } catch (InterruptedException e) { Log.i("", "### 请求分发器退出"); } }
Response缓存
针对于缓存,我们添加了一个简单的缓存接口。该接口是一个泛型接口,key和value的类型都是泛型。设计为泛型是因为我们在后续的框架中还会使用,后续的ImageLoader框架将以SimpleNet框架为基础来构建一个图片加载框架,其中也会用到缓存接口,但是它的类型却是不一样的,因此我们使用泛型来保证它的扩扩展性。
/** * 请求缓存接口 * * @author mrsimple * @param <K> key的类型 * @param <V> value类型 */ public interface Cache<K, V> { public V get(K key); public void put(K key, V value); public void remove(K key); }
针对于网络请求的缓存,我们的实现是LruMemCache类,该类将Response请求结果按照LRU的规则进行缓存。代码如下 :
/** * 将请求结果缓存到内存中 * * @author mrsimple */ public class LruMemCache implements Cache<String, Response> { /** * Reponse缓存 */ private LruCache<String, Response> mResponseCache; public LruMemCache() { // 计算可使用的最大内存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 取八分之一的可用内存作为缓存 final int cacheSize = maxMemory / 8; mResponseCache = new LruCache<String, Response>(cacheSize) { @Override protected int sizeOf(String key, Response response) { return response.rawData.length / 1024; } }; } @Override public Response get(String key) { return mResponseCache.get(key); } @Override public void put(String key, Response response) { mResponseCache.put(key, response); } @Override public void remove(String key) { mResponseCache.remove(key); } }
缓存类对象是各个NetworkExecutor共享的,它定义在NetworkExecutor中,如下 :
/** * 请求缓存 */ private static Cache<String, Response> mReqCache = new LruMemCache();
这样,多个NetworkExecutor就可以拥有同一份缓存了。
github地址
结束语
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。