前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类。我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpStack有两个实现类。

其中HttpCliantStack是在2.3以下使用,Hurl是在2.3以上使用,这样分开的原因谷歌给了注释。

  // Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html

2.3以下HttpUrlConnection 是不能用的,而2.3以上就是采用HttpUrlConnection 进行连接的,以下就是直接用的HttpClient。

HttpStack

先来看一下HttpStack接口

public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*通过给定的参数执行一个http请求
* <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
* and the Content-Type header is set to request.getPostBodyContentType().</p>
*
* @param request the request to perform//要执行的请求
* @param additionalHeaders additional headers to be sent together with
* {@link Request#getHeaders()}
* @return the HTTP response//执行一个请求返回一个结果
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError; }

HttpCliantStack

这里区分Get和Post请求,我们先看下HttpCliantStack,注释已经写的非常清楚了,如果注释有误望大家指出。

/**
* An HttpStack that performs request over an {@link HttpClient}.
* HttpStack:通过HttpClient执行请求
* {@link Volley#newRequestQueue(android.content.Context, HttpStack)}
*/
public class HttpClientStack implements HttpStack { protected final HttpClient mClient;//默认HttpClient /** The Constant HEADER_CONTENT_TYPE. */
private final static String HEADER_CONTENT_TYPE = "Content-Type"; /**
* Instantiates a new http client stack.
* Volley中HttpClient可是AndroidHttpClient.newInstance(userAgent)产生的
* @param client the client
*/
public HttpClientStack(HttpClient client) {
mClient = client;
} /**
* Adds the headers.
*
* @param httpRequest the http request
* @param headers the headers
*/
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
for (String key : headers.keySet()) {
httpRequest.setHeader(key, headers.get(key));
}
} /**
* Gets the post parameter pairs.
*
* @param postParams the post params
* @return the post parameter pairs
*/
@SuppressWarnings("unused")
private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {
List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size());
for (String key : postParams.keySet()) {
result.add(new BasicNameValuePair(key, postParams.get(key)));
}
return result;
} /* (non-Javadoc)
* @see com.android.volley.toolbox.HttpStack#performRequest(com.android.volley.Request, java.util.Map)
*/ @Override//中心方法
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);//设置请求方法
addHeaders(httpRequest, additionalHeaders);//添加自定义头部
addHeaders(httpRequest, request.getHeaders());//添加请求自带头部
onPrepareRequest(httpRequest);//相当于onStart,子类扩展
HttpParams httpParams = httpRequest.getParams();//获取配置类
int timeoutMs = request.getTimeoutMs();
// TODO: Reevaluate this connection timeout based on more wide-scale
// data collection and possibly different for wifi vs. 3G.
/** 如果有更大规模的数据在Wifi和3G网络下重新评估连接超时*/
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);//设置超时
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);//设置超时
return mClient.execute(httpRequest);
} /**
* Creates the appropriate subclass of HttpUriRequest for passed in request.
* 请求工厂类{GET,DELET,PUT,POST}
* @param request the request
* @param additionalHeaders the additional headers
* @return the http uri request
* @throws AuthFailureError the auth failure error
*/
@SuppressWarnings("deprecation")
/* protected */ static HttpUriRequest createHttpRequest(Request<?> request,
Map<String, String> additionalHeaders) throws AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST: {
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET. Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());
HttpEntity entity;
entity = new ByteArrayEntity(postBody);
postRequest.setEntity(entity);
return postRequest;
} else {
return new HttpGet(request.getUrl());
}
}
case Method.GET:
return new HttpGet(request.getUrl());
case Method.DELETE:
return new HttpDelete(request.getUrl());
case Method.POST: {
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(postRequest, request);
return postRequest;
}
case Method.PUT: {
HttpPut putRequest = new HttpPut(request.getUrl());
putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(putRequest, request);
return putRequest;
}
default:
throw new IllegalStateException("Unknown request method.");
}
} /**
* Sets the entity if non empty body.
* 非空体Entity
* @param httpRequest the http request
* @param request the request
* @throws AuthFailureError the auth failure error
*/
private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,
Request<?> request) throws AuthFailureError {
byte[] body = request.getBody();
if (body != null) {
HttpEntity entity = new ByteArrayEntity(body);
httpRequest.setEntity(entity);
}
} /**
* Called before the request is executed using the underlying HttpClient.
* 在请求之前调用
* <p>Overwrite in subclasses to augment the request.</p>
* 由子类覆写扩展
* @param request the request
* @throws IOException Signals that an I/O exception has occurred.
*/
protected void onPrepareRequest(HttpUriRequest request) throws IOException {
// Nothing.
}
}

它的构造参数是一个HttpClient,Velloy是用AndroidHttpClient.newInstance(userAgent)建立一个HttpClient实例。

再看这个类的最重要方法也就是对HttpStack接口的performRequest()方法进行具体实现。

第一步:通过这个静态方法createHttpRequest()来获取一个HttpUriRequest请求实例,其中HttpGet,HttpPost,HttpPut,HttpDelete都实现了HttpUriRequest这个接口。

这步就确定了请求类型和创立了Http实际请求。

第二步:通过这两个方法添加Http头部,

addHeaders(httpRequest, additionalHeaders);//添加自定义头部
addHeaders(httpRequest, request.getHeaders());//添加请求自带头部

第三步:这个方法

onPrepareRequest()

挺人性化的,相当于AsyncTask的onPreExecute(),不过要实现这个方法需要自行扩展此类,谷歌没有把她提出来。

一开始我还以为没有类似的方法,像Afinal的方法名字取得很吸引人,叫onStart(),onSuccess(),onFailure()。其实在Volley与之相对应的都有,onResponse就相当于onSuccess(),onErrorResponse就相当于onFailure(),而onPrepareRequest()就对应onStart()。

第四步:设置超时,这个超时设置值是在Request里封装进去了,Request封装了很多东西,比如请求的URL等。

在此谷歌在超时这里做了很温馨的提示,设置连接超时考虑WIFI和3G网络设置不一样,这里应该可以留出一个缺口,根据实际网络设置不一样的时常。貌似现在很多应用会根据网络来进行内容排版,例如什么无图模式啊,仅在wifi下上传等。

HurlStack

先看下构造,看来大框架构造都是按这格式的。

 /**
* 默认的构造器
* {@link Volley#newRequestQueue(android.content.Context, HttpStack)}
*/
public HurlStack() {
this(null);
} /**
* @param urlRewriter Rewriter to use for request URLs
*/
public HurlStack(UrlRewriter urlRewriter) {
this(urlRewriter, null);
} /**
* 两个主要参数
* @param urlRewriter Rewriter to use for request URLs//Url转换器
* @param sslSocketFactory SSL factory to use for HTTPS connections//安全连接
*/
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
mUrlRewriter = urlRewriter;
mSslSocketFactory = sslSocketFactory;
}

由此可见主要字段就是mUrlRewriter 和mSslSocketFactory 。前面的是URL转换接口,后面是安全连接。

这个URL转换接口还是挺人性化的,可以过滤些非法字符和省略Http或者www.

 public interface UrlRewriter {
/**
* Returns a URL to use instead of the provided one, or null to indicate
* this URL should not be used at all.
*/
public String rewriteUrl(String originalUrl);
}

然后我们还是看HttpStack接口的performRequest()方法实现。

@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();//获取这个请求的url
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {//默认的不会对url转换
String rewritten = mUrlRewriter.rewriteUrl(url);//实现UrlRewriter#rewriteUrl方法
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);//解析后Url
HttpURLConnection connection = openConnection(parsedUrl, request);
for (String headerName : map.keySet()) {//为connection添加属性
connection.addRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);//设置请求方法
// Initialize HttpResponse with data from the HttpURLConnection.
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
int responseCode = connection.getResponseCode();
if (responseCode == -1) {//不能取回ResponseCode
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);//通过responseStatus获得一个BasicHttpResponse
response.setEntity(entityFromConnection(connection));//设置Entity
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//header
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}

第一步:获取请求地址url,如果写了UrlRewriter就会按照这个接口的规则更改URL。

第二步:建立URL,通过createConnection()方法获得一个HttpURLConnection,通过openConnection()方法设置一些超时类的Http配置,然后添加头部,并且通过setConnectionParametersForRequest()方法设置HttpURLConnection的请求方法(PUT.GET,POST,DELETE...)。

第三步:然后通过HttpURLConnection获取ResponseCode,ResponseMessage,ResponseStatus,BasicHttpResponse响应结果,并进行响应处理。

第四步:通过entityFromConnection(),把HttpURLConnection获得的流转化为HttpEntity,并返回带HttpEntity的HttpResponse。

 /**
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
* 从HttpURLConnection获取一个HttpEntity
* @param connection
* @return an HttpEntity populated with data from <code>connection</code>.
*/
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream;//首先从HttpURLConnection获取一个输入流
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
entity.setContent(inputStream);//把流设置为HttpEntity的Content
entity.setContentLength(connection.getContentLength());//设置内容长度
entity.setContentEncoding(connection.getContentEncoding());//设置编码格式
entity.setContentType(connection.getContentType());//设置内容类型
return entity;
}

为什么HurlStack没有onPrepareRequest()方法,如果要的话那就只有知己加了。

来看扩展HttpClientStack的一个类:

public class IpadHttpStack extends  HttpClientStack{

    interface OnStartListener{
void onStart(HttpUriRequest request);
} OnStartListener mOnStartListener;
static String ua = "ipad"; public IpadHttpStack() {
super(AndroidHttpClient.newInstance(ua));
// TODO Auto-generated constructor stub
} @Override
protected void onPrepareRequest(HttpUriRequest request) throws IOException {
// TODO Auto-generated method stub
super.onPrepareRequest(request);
if(mOnStartListener!=null)
mOnStartListener.onStart(request);
} public void setOnStartListener(OnStartListener listener) {
this.mOnStartListener = listener;
} }

这是测试类,访问路由器网关。

public class MainActivity extends Activity {
RequestQueue mQueue;
IpadHttpStack bvinHttp;
private static HashSet<Class<?>> exeptionList = new HashSet<Class<?>>();
static{
exeptionList.add(AuthFailureError.class);
exeptionList.add(NetworkError.class);
exeptionList.add(NoConnectionError.class);
exeptionList.add(ParseError.class);
exeptionList.add(ServerError.class);
exeptionList.add(TimeoutError.class);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.e("onResponse","sdgdsg");
bvinHttp = new IpadHttpStack();
mQueue = Volley.newRequestQueue(getApplicationContext(),bvinHttp);
//StringRequest四个构造参数分别是Request类型,url,网络请求响应监听器,错误监听器
bvinHttp.setOnStartListener(new IpadHttpStack.OnStartListener() { @Override
public void onStart(HttpUriRequest request) {
// TODO Auto-generated method stub }
});
Authenticator.setDefault(new Authenticator() { @Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return new PasswordAuthentication("admin", "admin".toCharArray());
} });
mQueue.add(new StringRequest(Method.GET, "http://192.168.1.1", new Listener<String>(){ @Override
public void onResponse(String arg0) {
// TODO Auto-generated method stub
Log.e("onResponse", arg0);
} }, new ErrorListener(){ @Override
public void onErrorResponse(VolleyError arg0) {
// TODO Auto-generated method stub
if (arg0 instanceof TimeoutError) {
Log.e("onErrorResponse", "超时");
}else if(arg0 instanceof AuthFailureError){
Log.e("AuthFailureError", arg0.toString());
}
Log.e("AuthFailureError", arg0.toString());
//exeptionList.contains(arg0)
} }));
mQueue.start();
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
mQueue.stop();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add("取消");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
mQueue.cancelAll(new RequestFilter(){ @Override
public boolean apply(Request<?> arg0) {
// TODO Auto-generated method stub
arg0.cancel();
return false;
}});
return super.onOptionsItemSelected(item);
} }

谷歌Volley网络框架讲解——HttpStack及其实现类的更多相关文章

  1. 谷歌Volley网络框架讲解——Network及其实现类

    我们看到Network接口只有一个实现类BasicNetwork,而HttpStack有两个实现类. BasicNetwork这个类是toolbox工具箱包里的,实现了Network接口. 先来看下N ...

  2. 谷歌Volley网络框架讲解——BasicNetwork类

    谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...

  3. 谷歌Volley网络框架讲解——第一篇

    自从公司新招了几个android工程师后,我清闲了些许.于是就可以有时间写写博客,研究一些没来的研究的东西. 今年的谷歌IO大会上,谷歌推出了自己的网络框架——Volley.不久前就听说了但是没有cl ...

  4. 谷歌Volley网络框架讲解——网络枢纽

    研究了这么久的Volley,愈来愈发现这个框架的精美和人性化.比起民间一些框架强很多,一开始总是盲人摸象找不到头绪,现在终于有些明朗了.Volley其实就是一个请求队列的代理类,我们看下UML. 这就 ...

  5. Volley网络框架的使用

    Volley的特点:   使用网络通信更快.更简单 Get/Post网络请求网络图像的高效率异步请求 可以对网络请求的优先级进行排序处理 可以进行网络请求的缓存 可以取消多级别请求 可以和Activi ...

  6. Volley网络框架完全解析(缓存篇)

    在上一篇中讲完了Volley框架怎么使用,那么这篇就来讲讲Volley框架的缓存机制 我们看Volley内部源码发现: Volley框架内部自己处理了DiskBasedCache硬盘缓存,但是没有处理 ...

  7. Volley网络框架完全解析(使用篇)

    在Android中,网络请求无非就这两种:HttpURLConnection和HttpClient( Apache),我们在使用时一般都会对它们进行一系列的封装,但是这过程不免有些繁琐,所以,Goog ...

  8. Volley网络框架完全解析(实战篇)

    好了,今天就通过一个瀑布流demo,来使用Volley框架请求网络图片. 前言: 我们使用NetworkImageView显示图片: 1.因为该控件可以自动的管理好请求的生命周期,当与父控件detac ...

  9. Android 网络框架Volley的使用

    Volley简介 在平时的开发过程中,我们的应用几乎总是在和网络打交道, 在android下的网络编程一般都是基于Http协议的 ,常见的是HttpURLConnection和HttpClient 两 ...

随机推荐

  1. C 程序的存储空间记录

    一直以来,我们只是单纯的去运行执行 C 程序,并没有关心这个可执行文件里面包含着什么东西. 参考UNIX 环境高级编程 7.6,记录C程序的存储空间布局. C程序由 正文段,初始化数据段,非初始化数据 ...

  2. Winform控件:保存文件对话框(SaveFileDialog)

    SaveFileDialog用于保存文件 1.新建Winform窗体应用程序,命名为SaveFileDialogDemo. 2.在界面上添加一个按钮的控件(用于打开保存文件对话框),添加文本控件,用于 ...

  3. Rails NameError uninitialized constant class solution

    rails nameerror uninitialized constant class will occur if your rails console is not loaded with con ...

  4. MFC 窗体样式修改

    窗体创建之后,如何设置窗体的样式呢? 一般情况下使用GetWindowLongW与SetWindowLongW即可实现窗体样式的修改或者使用ModifyStyle. 关于MFC存在GetWindowL ...

  5. vlc player验证交换机igmp

    使用vlc media player发送多播数据,验证交换机igmp的设置是否成功. 链接 http://peakdrive.com/?p=440 http://www.dasblinkenlicht ...

  6. Spring Tools Suite (STS) 简介

    首先,sts是一个定制版的Eclipse,专为Spring开发定制的,方便创建调试运行维护Spring应用. 官方页面.下载地址(3.8.1 win x64). 其次,没什么好介绍的,用一下就明白了. ...

  7. mysql_query error:Commands out of sync;you can't run this command now

    MYSQL_REST *result没有释放, 用mysql_free_result(result)即可.

  8. (转)获取android源码时repo的错误

    获取android源码时repo的错误 今天用repo获取android源码:../bin/repo init -u git://android.git.kernel.org/platform/man ...

  9. php date strtotime的用法

    1.上个月第一天及最后一天. echo date('Y-m-01', strtotime('-1 month')); echo strtotime(date('Y-m-01 0:00:00', str ...

  10. Jmeter零起点学习

    什么是JMeter   Apache JMeter是一个开源的Java桌面软件.设计的目的就是进行C/S架构软件的负载测试.随着发展,有很多人也用来进行一些静态资源或者动态资源的性能测试.可以支持的测 ...