前言
在教你写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地址