教你写Android网络框架之Request、Response类与请求队列
2015-02-03 14:53
567 查看
转载请注明出处,本文来自【 Mr.Simple的博客 】。
我正在参加博客之星,点击这里投我一票吧,谢谢~
正如你所看到的,这系列博客是为新人准备的,如果你是高手,请忽略。
在框架开发当中,很重要的一点就是抽象。也就是面向对象中重要的一条原则: 依赖倒置原则,简单来说就是要依赖抽象,而不依赖具体。这样就使得我们的框架具有可扩展性,同时也满足了开闭原则,即对扩展开放,对修改关闭。针对于我们的网络框架来说,最重要的抽象就是Reqeust类、Response类,因此今天我们就从两个类开始切入。最后我们再引入网络框架中的请求队列(RequestQueue),这是SimpleNet中的中枢神经,所有的请求都需要放到该队列,然后等待着被执行。请求队列就像工厂中的流水线一样,而网络请求就像流水线上的待加工的产品。执行网络请求的对象就类似工厂中的工人,在自己的岗位上等待流水线上传递过来的产品,然后对其加工,加工完就将产品放到其他的位置。它们角色对应关系参考图1,如对SimpleNet的一些角色不太清楚可参考教你写Android网络框架之基本架构一文。
/**
* 网络请求类. 注意GET和DELETE不能传递请求参数,因为其请求的性质所致,用户可以将参数构建到url后传递进来到Request中.
*
* @author mrsimple
* @param <T> T为请求返回的数据类型
*/
public abstract class Request<T> implements Comparable<Request<T>> {
/**
* http请求方法枚举,这里我们只有GET, POST, PUT, DELETE四种
*
* @author mrsimple
*/
public static enum HttpMethod {
GET("GET"),
POST("POST"),
PUT("PUT"),
DELETE("DELETE");
/** http request type */
private String mHttpMethod = "";
private HttpMethod(String method) {
mHttpMethod = method;
}
@Override
public String toString() {
return mHttpMethod;
}
}
/**
* 优先级枚举
*
* @author mrsimple
*/
public static enum Priority {
LOW,
NORMAL,
HIGN,
IMMEDIATE
}
/**
* Default encoding for POST or PUT parameters. See
* {@link #getParamsEncoding()}.
*/
private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
/**
* 请求序列号
*/
protected int mSerialNum = 0;
/**
* 优先级默认设置为Normal
*/
protected Priority mPriority = Priority.NORMAL;
/**
* 是否取消该请求
*/
protected boolean isCancel = false;
/** 该请求是否应该缓存 */
private boolean mShouldCache = true;
/**
* 请求Listener
*/
protected RequestListener<T> mRequestListener;
/**
* 请求的url
*/
private String mUrl = "";
/**
* 请求的方法
*/
HttpMethod mHttpMethod = HttpMethod.GET;
/**
* 请求的header
*/
private Map<String, String> mHeaders = new HashMap<String, String>();
/**
* 请求参数
*/
private Map<String, String> mBodyParams = new HashMap<String, String>();
/**
* @param method
* @param url
* @param listener
*/
public Request(HttpMethod method, String url, RequestListener<T> listener) {
mHttpMethod = method;
mUrl = url;
mRequestListener = listener;
}
/**
* 从原生的网络请求中解析结果,子类覆写
*
* @param response
* @return
*/
public abstract T parseResponse(Response response);
/**
* 处理Response,该方法运行在UI线程.
*
* @param response
*/
public final void deliveryResponse(Response response) {
// 解析得到请求结果
T result = parseResponse(response);
if (mRequestListener != null) {
int stCode = response != null ? response.getStatusCode() : -1;
String msg = response != null ? response.getMessage() : "unkown error";
mRequestListener.onComplete(stCode, result, msg);
}
}
public String getUrl() {
return mUrl;
}
public int getSerialNumber() {
return mSerialNum;
}
public void setSerialNumber(int mSerialNum) {
this.mSerialNum = mSerialNum;
}
public Priority getPriority() {
return mPriority;
}
public void setPriority(Priority mPriority) {
this.mPriority = mPriority;
}
protected String getParamsEncoding() {
return DEFAULT_PARAMS_ENCODING;
}
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
}
public HttpMethod getHttpMethod() {
return mHttpMethod;
}
public Map<String, String> getHeaders() {
return mHeaders;
}
public Map<String, String> getParams() {
return mBodyParams;
}
public void cancel() {
isCancel = true;
}
public boolean isCanceled() {
return isCancel;
}
/**
* 返回POST或者PUT请求时的Body参数字节数组
*
*/
public byte[] getBody() {
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
return encodeParameters(params, getParamsEncoding());
}
return null;
}
/**
* 将参数转换为Url编码的参数串
*/
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
StringBuilder encodedParams = new StringBuilder();
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
encodedParams.append('=');
encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
encodedParams.append('&');
}
return encodedParams.toString().getBytes(paramsEncoding);
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
}
}
// 用于对请求的排序处理,根据优先级和加入到队列的序号进行排序
@Override
public int compareTo(Request<T> another) {
Priority myPriority = this.getPriority();
Priority anotherPriority = another.getPriority();
// 如果优先级相等,那么按照添加到队列的序列号顺序来执行
return myPriority.equals(another) ? this.getSerialNumber() - another.getSerialNumber()
: myPriority.ordinal() - anotherPriority.ordinal();
}
/**
* 网络请求Listener,会被执行在UI线程
*
* @author mrsimple
* @param <T> 请求的response类型
*/
public static interface RequestListener<T> {
/**
* 请求完成的回调
*
* @param response
*/
public void onComplete(int stCode, T response, String errMsg);
}
}
上述代码Request<T>为抽象类,T则为该请求Response的数据格式。这个T是请求类中的一个比较重要的点,不同的人有不同的需求,即请求Reponse的数据格式并不是都是一样的,我们必须考虑到请求返回类型的多样性,用泛型T来表示返回的数据格式类型,然后Request子类覆写对应的方法实现解析Response的数据格式,最后调用请求Listener将请求结果执行在UI线程,这样整个请求就完成了。
每个Request都有一个序列号,该序列号由请求队列生成,标识该请求在队列中的序号,该序号和请求优先级决定了该请求在队列中的排序,即它在请求队列的执行顺序。每个请求有请求方式,例如"POST"、"GET",这里我们用枚举来代替,具名类型比单纯的字符串更易于使用。每个Request都可以添加Header、Body参数
( 关于请求参数的格式可以参考 四种常见的 POST 提交数据方式),并且可以取消。抽象类封装了通用的代码,只有可变的部分是抽象函数,这里只有parseResponse这个函数。
例如,我们返回的数据格式是Json,那么我们构建一个子类叫做JsonRequest,示例代码如下。
/**
* 返回的数据类型为Json的请求, Json对应的对象类型为JSONObject
*
* @author mrsimple
*/
public class JsonRequest extends Request<JSONObject> {
public JsonRequest(HttpMethod method, String url, RequestListener<JSONObject> listener) {
super(method, url, listener);
}
/**
* 将Response的结果转换为JSONObject
*/
@Override
public JSONObject parseResponse(Response response) {
String jsonString = new String(response.getRawData());
try {
return new JSONObject(jsonString);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
可以看到,实现一个请求类还是非常简单的,只需要覆写parseResponse函数来解析你的请求返回的数据即可。这样就保证了可扩展性,比如后面如果我想使用这个框架来做一个ImageLoader,那么我可以创建一个ImageRequest,该请求返回的类型就是Bitmap,那么我们只需要覆写parseResponse函数,然后把结果转换成Bitmap即可。
这里引入了Response类,这个Response类存储了请求的状态码、请求结果等内容,我们继续往下看。
/**
* 请求结果类,继承自BasicHttpResponse,将结果存储在rawData中.
* @author mrsimple
*/
public class Response extends BasicHttpResponse {
public byte[] rawData = new byte[0];
public Response(StatusLine statusLine) {
super(statusLine);
}
public Response(ProtocolVersion ver, int code, String reason) {
super(ver, code, reason);
}
@Override
public void setEntity(HttpEntity entity) {
super.setEntity(entity);
rawData = entityToBytes(getEntity());
}
public byte[] getRawData() {
return rawData;
}
public int getStatusCode() {
return getStatusLine().getStatusCode();
}
public String getMessage() {
return getStatusLine().getReasonPhrase();
}
/** Reads the contents of HttpEntity into a byte[]. */
private byte[] entityToBytes(HttpEntity entity) {
try {
return EntityUtils.toByteArray(entity);
} catch (IOException e) {
e.printStackTrace();
}
return new byte[0];
}
}
这个类很简单,只是继承了BasicHttpResponse,然后将输入流转换成字节数组,然后包装了几个常用的方法,主要是为了使用简单吧。我们将结果存储为字节数组,这样可以用户可以很方便的将结果转换为String、bitmap等数据类型,如果直接存储的是InputStream,那么在很多时候用户需要在外围将InputStream先转换为字节数组,然后再转换为最终的格式,例如InputStream转为String类型。这也是为什么我们这里选用byte[]而不用InputStream的原因。
( 子线程 )来从请求队列中获取请求,并且执行请求。请求队列会根据请求的优先级进行排序,这样就保证了一些优先级高的请求得到尽快的处理,这也就是为什么Request类中实现了Comparable接口的原因。如果优先级一致的情况下,则会根据请求加入到队列的顺序来排序,这个序号由请求队列生成,这样就保证了优先级一样的情况下按照FIFO的策略执行。
/**
* 请求队列, 使用优先队列,使得请求可以按照优先级进行处理. [ Thread Safe ]
*
* @author mrsimple
*/
public final class RequestQueue {
/**
* 请求队列 [ Thread-safe ]
*/
private BlockingQueue<Request<?>> mRequestQueue = new PriorityBlockingQueue<Request<?>>();
/**
* 请求的序列化生成器
*/
private AtomicInteger mSerialNumGenerator = new AtomicInteger(0);
/**
* 默认的核心数
*/
public static int DEFAULT_CORE_NUMS = Runtime.getRuntime().availableProcessors() + 1;
/**
* CPU核心数 + 1个分发线程数
*/
private int mDispatcherNums = DEFAULT_CORE_NUMS;
/**
* NetworkExecutor,执行网络请求的线程
*/
private NetworkExecutor[] mDispatchers = null;
/**
* Http请求的真正执行者
*/
private HttpStack mHttpStack;
/**
* @param coreNums 线程核心数
*/
protected RequestQueue(int coreNums, HttpStack httpStack) {
mDispatcherNums = coreNums;
mHttpStack = httpStack != null ? httpStack : HttpStackFactory.createHttpStack();
}
/**
* 启动NetworkExecutor
*/
private final void startNetworkExecutors() {
mDispatchers = new NetworkExecutor[mDispatcherNums];
for (int i = 0; i < mDispatcherNums; i++) {
mDispatchers[i] = new NetworkExecutor(mRequestQueue, mHttpStack);
mDispatchers[i].start();
}
}
public void start() {
stop();
startNetworkExecutors();
}
/**
* 停止NetworkExecutor
*/
public void stop() {
if (mDispatchers != null && mDispatchers.length > 0) {
for (int i = 0; i < mDispatchers.length; i++) {
mDispatchers[i].quit();
}
}
}
/**
* 不能重复添加请求
*
* @param request
*/
public void addRequest(Request<?> request) {
if (!mRequestQueue.contains(request)) {
request.setSerialNumber(this.generateSerialNumber());
mRequestQueue.add(request);
} else {
Log.d("", "### 请求队列中已经含有");
}
}
public void clear() {
mRequestQueue.clear();
}
public BlockingQueue<Request<?>> getAllRequests() {
return mRequestQueue;
}
/**
* 为每个请求生成一个系列号
*
* @return 序列号
*/
private int generateSerialNumber() {
return mSerialNumGenerator.incrementAndGet();
}
}
这里引入了一个HttpStack,这是一个接口,只有一个函数。该接口定义了执行网络请求的抽象,代码如下:
[java] view
plaincopy
/**
* 执行网络请求的接口
*
* @author mrsimple
*/
public interface HttpStack {
/**
* 执行Http请求
*
* @param request 待执行的请求
* @return
*/
public Response performRequest(Request<?> request);
}
今天就先到这里吧,关于HttpStack、NetworkExecutor、ResponseDelivery的介绍将在下一篇博客中更新,敬请期待。
如果你看到这里都不给我投一篇,那简直太不够意思了!!点击这里投我一票吧,谢谢~
我正在参加博客之星,点击这里投我一票吧,谢谢~
前言
在教你写Android网络框架之基本架构一文中我们已经介绍了SimpleNet网络框架的基本结构,今天我们就开始从代码的角度来开始切入该网络框架的实现,在剖析的同时我们会分析设计思路,以及为什么要这样做,这样做的好处是什么。这样我们不仅学到了如何实现网络框架,也会学到设计一个通用的框架应该有哪些考虑,这就扩展到框架设计的范畴,通过这个简单的实例希望能给新人一些帮助。当然这只是一家之言,大家都可以有自己的实现思路。正如你所看到的,这系列博客是为新人准备的,如果你是高手,请忽略。
在框架开发当中,很重要的一点就是抽象。也就是面向对象中重要的一条原则: 依赖倒置原则,简单来说就是要依赖抽象,而不依赖具体。这样就使得我们的框架具有可扩展性,同时也满足了开闭原则,即对扩展开放,对修改关闭。针对于我们的网络框架来说,最重要的抽象就是Reqeust类、Response类,因此今天我们就从两个类开始切入。最后我们再引入网络框架中的请求队列(RequestQueue),这是SimpleNet中的中枢神经,所有的请求都需要放到该队列,然后等待着被执行。请求队列就像工厂中的流水线一样,而网络请求就像流水线上的待加工的产品。执行网络请求的对象就类似工厂中的工人,在自己的岗位上等待流水线上传递过来的产品,然后对其加工,加工完就将产品放到其他的位置。它们角色对应关系参考图1,如对SimpleNet的一些角色不太清楚可参考教你写Android网络框架之基本架构一文。
Request类
既然网络框架,那么我们先从网络请求类开始。前文已经说过,既然是框架,那么就需要可扩展性。因此注定了Request是抽象,而不是具体。而对于网络请求来说,用户得到的请求结果格式是不确定,比如有的服务器返回的是json,有的返回的是xml,有的直接是字符串。但是对于Http Response来说,它的返回数据类型都是Stream,也就是我们得到的原始数据都是二进制的流。所以在Request基类中我们必须预留方法来解析Response返回的具体类型,虽然返回的类型不同,但是他们的处理逻辑是一样的,因此我们可把Request作为泛型类,它的泛型类型就是它的返回数据类型,比如Request<String>,那么它的返回数据类型就是String类型的。另外还有请求的优先级、可取消等,我们这里先给出核心代码,然后再继续分析。/**
* 网络请求类. 注意GET和DELETE不能传递请求参数,因为其请求的性质所致,用户可以将参数构建到url后传递进来到Request中.
*
* @author mrsimple
* @param <T> T为请求返回的数据类型
*/
public abstract class Request<T> implements Comparable<Request<T>> {
/**
* http请求方法枚举,这里我们只有GET, POST, PUT, DELETE四种
*
* @author mrsimple
*/
public static enum HttpMethod {
GET("GET"),
POST("POST"),
PUT("PUT"),
DELETE("DELETE");
/** http request type */
private String mHttpMethod = "";
private HttpMethod(String method) {
mHttpMethod = method;
}
@Override
public String toString() {
return mHttpMethod;
}
}
/**
* 优先级枚举
*
* @author mrsimple
*/
public static enum Priority {
LOW,
NORMAL,
HIGN,
IMMEDIATE
}
/**
* Default encoding for POST or PUT parameters. See
* {@link #getParamsEncoding()}.
*/
private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
/**
* 请求序列号
*/
protected int mSerialNum = 0;
/**
* 优先级默认设置为Normal
*/
protected Priority mPriority = Priority.NORMAL;
/**
* 是否取消该请求
*/
protected boolean isCancel = false;
/** 该请求是否应该缓存 */
private boolean mShouldCache = true;
/**
* 请求Listener
*/
protected RequestListener<T> mRequestListener;
/**
* 请求的url
*/
private String mUrl = "";
/**
* 请求的方法
*/
HttpMethod mHttpMethod = HttpMethod.GET;
/**
* 请求的header
*/
private Map<String, String> mHeaders = new HashMap<String, String>();
/**
* 请求参数
*/
private Map<String, String> mBodyParams = new HashMap<String, String>();
/**
* @param method
* @param url
* @param listener
*/
public Request(HttpMethod method, String url, RequestListener<T> listener) {
mHttpMethod = method;
mUrl = url;
mRequestListener = listener;
}
/**
* 从原生的网络请求中解析结果,子类覆写
*
* @param response
* @return
*/
public abstract T parseResponse(Response response);
/**
* 处理Response,该方法运行在UI线程.
*
* @param response
*/
public final void deliveryResponse(Response response) {
// 解析得到请求结果
T result = parseResponse(response);
if (mRequestListener != null) {
int stCode = response != null ? response.getStatusCode() : -1;
String msg = response != null ? response.getMessage() : "unkown error";
mRequestListener.onComplete(stCode, result, msg);
}
}
public String getUrl() {
return mUrl;
}
public int getSerialNumber() {
return mSerialNum;
}
public void setSerialNumber(int mSerialNum) {
this.mSerialNum = mSerialNum;
}
public Priority getPriority() {
return mPriority;
}
public void setPriority(Priority mPriority) {
this.mPriority = mPriority;
}
protected String getParamsEncoding() {
return DEFAULT_PARAMS_ENCODING;
}
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
}
public HttpMethod getHttpMethod() {
return mHttpMethod;
}
public Map<String, String> getHeaders() {
return mHeaders;
}
public Map<String, String> getParams() {
return mBodyParams;
}
public void cancel() {
isCancel = true;
}
public boolean isCanceled() {
return isCancel;
}
/**
* 返回POST或者PUT请求时的Body参数字节数组
*
*/
public byte[] getBody() {
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
return encodeParameters(params, getParamsEncoding());
}
return null;
}
/**
* 将参数转换为Url编码的参数串
*/
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
StringBuilder encodedParams = new StringBuilder();
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
encodedParams.append('=');
encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
encodedParams.append('&');
}
return encodedParams.toString().getBytes(paramsEncoding);
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
}
}
// 用于对请求的排序处理,根据优先级和加入到队列的序号进行排序
@Override
public int compareTo(Request<T> another) {
Priority myPriority = this.getPriority();
Priority anotherPriority = another.getPriority();
// 如果优先级相等,那么按照添加到队列的序列号顺序来执行
return myPriority.equals(another) ? this.getSerialNumber() - another.getSerialNumber()
: myPriority.ordinal() - anotherPriority.ordinal();
}
/**
* 网络请求Listener,会被执行在UI线程
*
* @author mrsimple
* @param <T> 请求的response类型
*/
public static interface RequestListener<T> {
/**
* 请求完成的回调
*
* @param response
*/
public void onComplete(int stCode, T response, String errMsg);
}
}
上述代码Request<T>为抽象类,T则为该请求Response的数据格式。这个T是请求类中的一个比较重要的点,不同的人有不同的需求,即请求Reponse的数据格式并不是都是一样的,我们必须考虑到请求返回类型的多样性,用泛型T来表示返回的数据格式类型,然后Request子类覆写对应的方法实现解析Response的数据格式,最后调用请求Listener将请求结果执行在UI线程,这样整个请求就完成了。
每个Request都有一个序列号,该序列号由请求队列生成,标识该请求在队列中的序号,该序号和请求优先级决定了该请求在队列中的排序,即它在请求队列的执行顺序。每个请求有请求方式,例如"POST"、"GET",这里我们用枚举来代替,具名类型比单纯的字符串更易于使用。每个Request都可以添加Header、Body参数
( 关于请求参数的格式可以参考 四种常见的 POST 提交数据方式),并且可以取消。抽象类封装了通用的代码,只有可变的部分是抽象函数,这里只有parseResponse这个函数。
例如,我们返回的数据格式是Json,那么我们构建一个子类叫做JsonRequest,示例代码如下。
/**
* 返回的数据类型为Json的请求, Json对应的对象类型为JSONObject
*
* @author mrsimple
*/
public class JsonRequest extends Request<JSONObject> {
public JsonRequest(HttpMethod method, String url, RequestListener<JSONObject> listener) {
super(method, url, listener);
}
/**
* 将Response的结果转换为JSONObject
*/
@Override
public JSONObject parseResponse(Response response) {
String jsonString = new String(response.getRawData());
try {
return new JSONObject(jsonString);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
可以看到,实现一个请求类还是非常简单的,只需要覆写parseResponse函数来解析你的请求返回的数据即可。这样就保证了可扩展性,比如后面如果我想使用这个框架来做一个ImageLoader,那么我可以创建一个ImageRequest,该请求返回的类型就是Bitmap,那么我们只需要覆写parseResponse函数,然后把结果转换成Bitmap即可。
这里引入了Response类,这个Response类存储了请求的状态码、请求结果等内容,我们继续往下看。
Response类
每个请求都对应一个Response,但这里的问题是这个Response的数据格式我们是不知道的。我们写的是框架,不是应用。框架只是构建一个基本环境,并且附带一些比较常用的类,比如这里的JsonRequest。但是重要的一点是可以让用户自由、简单的扩展以实现他的需求。对于Response类来说,我们最重要的一点就是要确定请求结果的数据格式类型。我们都知道,HTTP实际上是基于TCP协议,而TCP协议又是基于Socket,Socket实际上操作的也就是输入、输出流,输出流是向服务器写数据,输入流自然是从服务器读取数据。因此我们在Response类中应该使用InputStream存储结果或者使用更为易于使用的字节数组,这里我们使用字节数组来存储。我们来看Response类。/**
* 请求结果类,继承自BasicHttpResponse,将结果存储在rawData中.
* @author mrsimple
*/
public class Response extends BasicHttpResponse {
public byte[] rawData = new byte[0];
public Response(StatusLine statusLine) {
super(statusLine);
}
public Response(ProtocolVersion ver, int code, String reason) {
super(ver, code, reason);
}
@Override
public void setEntity(HttpEntity entity) {
super.setEntity(entity);
rawData = entityToBytes(getEntity());
}
public byte[] getRawData() {
return rawData;
}
public int getStatusCode() {
return getStatusLine().getStatusCode();
}
public String getMessage() {
return getStatusLine().getReasonPhrase();
}
/** Reads the contents of HttpEntity into a byte[]. */
private byte[] entityToBytes(HttpEntity entity) {
try {
return EntityUtils.toByteArray(entity);
} catch (IOException e) {
e.printStackTrace();
}
return new byte[0];
}
}
这个类很简单,只是继承了BasicHttpResponse,然后将输入流转换成字节数组,然后包装了几个常用的方法,主要是为了使用简单吧。我们将结果存储为字节数组,这样可以用户可以很方便的将结果转换为String、bitmap等数据类型,如果直接存储的是InputStream,那么在很多时候用户需要在外围将InputStream先转换为字节数组,然后再转换为最终的格式,例如InputStream转为String类型。这也是为什么我们这里选用byte[]而不用InputStream的原因。
请求队列
网络请求队列也比较简单,实际上就是内部封装了一个优先级队列,在构建队列时会启动几个NetworkExecutor( 子线程 )来从请求队列中获取请求,并且执行请求。请求队列会根据请求的优先级进行排序,这样就保证了一些优先级高的请求得到尽快的处理,这也就是为什么Request类中实现了Comparable接口的原因。如果优先级一致的情况下,则会根据请求加入到队列的顺序来排序,这个序号由请求队列生成,这样就保证了优先级一样的情况下按照FIFO的策略执行。
/**
* 请求队列, 使用优先队列,使得请求可以按照优先级进行处理. [ Thread Safe ]
*
* @author mrsimple
*/
public final class RequestQueue {
/**
* 请求队列 [ Thread-safe ]
*/
private BlockingQueue<Request<?>> mRequestQueue = new PriorityBlockingQueue<Request<?>>();
/**
* 请求的序列化生成器
*/
private AtomicInteger mSerialNumGenerator = new AtomicInteger(0);
/**
* 默认的核心数
*/
public static int DEFAULT_CORE_NUMS = Runtime.getRuntime().availableProcessors() + 1;
/**
* CPU核心数 + 1个分发线程数
*/
private int mDispatcherNums = DEFAULT_CORE_NUMS;
/**
* NetworkExecutor,执行网络请求的线程
*/
private NetworkExecutor[] mDispatchers = null;
/**
* Http请求的真正执行者
*/
private HttpStack mHttpStack;
/**
* @param coreNums 线程核心数
*/
protected RequestQueue(int coreNums, HttpStack httpStack) {
mDispatcherNums = coreNums;
mHttpStack = httpStack != null ? httpStack : HttpStackFactory.createHttpStack();
}
/**
* 启动NetworkExecutor
*/
private final void startNetworkExecutors() {
mDispatchers = new NetworkExecutor[mDispatcherNums];
for (int i = 0; i < mDispatcherNums; i++) {
mDispatchers[i] = new NetworkExecutor(mRequestQueue, mHttpStack);
mDispatchers[i].start();
}
}
public void start() {
stop();
startNetworkExecutors();
}
/**
* 停止NetworkExecutor
*/
public void stop() {
if (mDispatchers != null && mDispatchers.length > 0) {
for (int i = 0; i < mDispatchers.length; i++) {
mDispatchers[i].quit();
}
}
}
/**
* 不能重复添加请求
*
* @param request
*/
public void addRequest(Request<?> request) {
if (!mRequestQueue.contains(request)) {
request.setSerialNumber(this.generateSerialNumber());
mRequestQueue.add(request);
} else {
Log.d("", "### 请求队列中已经含有");
}
}
public void clear() {
mRequestQueue.clear();
}
public BlockingQueue<Request<?>> getAllRequests() {
return mRequestQueue;
}
/**
* 为每个请求生成一个系列号
*
* @return 序列号
*/
private int generateSerialNumber() {
return mSerialNumGenerator.incrementAndGet();
}
}
这里引入了一个HttpStack,这是一个接口,只有一个函数。该接口定义了执行网络请求的抽象,代码如下:
[java] view
plaincopy
/**
* 执行网络请求的接口
*
* @author mrsimple
*/
public interface HttpStack {
/**
* 执行Http请求
*
* @param request 待执行的请求
* @return
*/
public Response performRequest(Request<?> request);
}
今天就先到这里吧,关于HttpStack、NetworkExecutor、ResponseDelivery的介绍将在下一篇博客中更新,敬请期待。
如果你看到这里都不给我投一篇,那简直太不够意思了!!点击这里投我一票吧,谢谢~
Github地址
SimpleNet网络框架地址相关文章推荐
- Android网络框架之Request、Response类与请求队列(二)
- 教你写Android网络框架之Request、Response类与请求队列
- 教你写Android网络框架之Request、Response类与请求队列
- Android-Volley网络通信框架(自定义Request 请求:实现 GsonRequest)
- Android网络框架volley学习(九)请求结果Response<T>简析
- Android-Volley网络通信框架(二次封装数据请求和图片请求(包括处理请求队列和图片缓存))
- 教你写Android网络框架之请求配置与Response缓存
- 教你写Android网络框架之请求配置与Response缓存
- Android网络框架volley学习(五)请求队列RequestQueue简析
- XDroidRequest - 一款基于Android 6.0 网络请求框架
- android网络开源框架volley(三)——请求队列是主线
- Android-Volley网络通信框架(二次封装数据请求和图片请求(包含处理请求队列和图片缓存))
- 教你写Android网络框架之请求配置与Response缓存
- Android网络框架之请求配置与Response缓存(四)
- 开源项目之Android http请求及缓存框架(GalHttprequest)
- android Volley请求网络框架的使用(一)
- Android Volley网络请求框架 实现post方法并带Map参数上传
- Android 网络请求框架android-async-http问题
- iOS网络编程-ASIHTTPRequest小例子-数据请求队列
- android网络开源框架volley(二)——自定义你的请求对象