谷歌Volley网络框架讲解——HttpStack及其实现类
前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下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及其实现类的更多相关文章
- 谷歌Volley网络框架讲解——Network及其实现类
我们看到Network接口只有一个实现类BasicNetwork,而HttpStack有两个实现类. BasicNetwork这个类是toolbox工具箱包里的,实现了Network接口. 先来看下N ...
- 谷歌Volley网络框架讲解——BasicNetwork类
谷歌Volley网络框架讲解——BasicNetwork类 这个类是toolbox工具箱包里的,实现了Network接口. 先来看下Network这个interface,performRequest( ...
- 谷歌Volley网络框架讲解——第一篇
自从公司新招了几个android工程师后,我清闲了些许.于是就可以有时间写写博客,研究一些没来的研究的东西. 今年的谷歌IO大会上,谷歌推出了自己的网络框架——Volley.不久前就听说了但是没有cl ...
- 谷歌Volley网络框架讲解——网络枢纽
研究了这么久的Volley,愈来愈发现这个框架的精美和人性化.比起民间一些框架强很多,一开始总是盲人摸象找不到头绪,现在终于有些明朗了.Volley其实就是一个请求队列的代理类,我们看下UML. 这就 ...
- Volley网络框架的使用
Volley的特点: 使用网络通信更快.更简单 Get/Post网络请求网络图像的高效率异步请求 可以对网络请求的优先级进行排序处理 可以进行网络请求的缓存 可以取消多级别请求 可以和Activi ...
- Volley网络框架完全解析(缓存篇)
在上一篇中讲完了Volley框架怎么使用,那么这篇就来讲讲Volley框架的缓存机制 我们看Volley内部源码发现: Volley框架内部自己处理了DiskBasedCache硬盘缓存,但是没有处理 ...
- Volley网络框架完全解析(使用篇)
在Android中,网络请求无非就这两种:HttpURLConnection和HttpClient( Apache),我们在使用时一般都会对它们进行一系列的封装,但是这过程不免有些繁琐,所以,Goog ...
- Volley网络框架完全解析(实战篇)
好了,今天就通过一个瀑布流demo,来使用Volley框架请求网络图片. 前言: 我们使用NetworkImageView显示图片: 1.因为该控件可以自动的管理好请求的生命周期,当与父控件detac ...
- Android 网络框架Volley的使用
Volley简介 在平时的开发过程中,我们的应用几乎总是在和网络打交道, 在android下的网络编程一般都是基于Http协议的 ,常见的是HttpURLConnection和HttpClient 两 ...
随机推荐
- linqtosql 实现数据分页
cs代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syst ...
- JS地毯式学习四
1 窗口的位置 用来确定和修改 window 对象位置的属性和方法有很多. IE . Safari . Opera 和 Chrome都提供了 screenLeft 和 screenTop 属性,分别 ...
- Clipboard获取内容C#
一.获取文本 textBox1.Text = Clipboard.GetData("Text").ToString(); 二.获取图像 pictureBo ...
- fullcalendar案例一<原>
fullcalendar是个很强大的日历控件,可以用它进行排班.排会议.拍任务,很直观,用户体验良好. 看下效果图: #parse("index/head.vm") <lin ...
- spingboot集成jpa(二)
一.使用单元测试 单元测试在每个项目环境中必不可少,springboot中如何使用单元测试 在src/test/java中新建测试类DemoApplicationTest.java 项目结构: De ...
- ASP.NET 防止重复提交提示层
今天研究了下,其实我希望的很简单,就是有个封装好的提示层,等处理完后,刷新界面时 能自动消失 找了挺久的,找到这个控件还不错 完整Demo地址: http://download.csdn.net/de ...
- Hibernate- QBC-基本查询
01.环境搭建 02.基本查询 1.方法说明 方法 说明 Restrictions.eq = Restrictions.allEq 利用Map来进行多个等于的限制 Restrictions.gt &g ...
- xshell用ssh连接VMware中的ubuntu
SSH分客户端openssh-client和openssh-server如果你只是想登陆别的机器的SSH只需要安装openssh-client(ubuntu有默认安装,如果没有则sudo apt-ge ...
- HTML5之IndexedDB使用详解
随着firefox4正式版的推出,IndexedDB正式进入我们的视线.IndexedDB是HTML5-WebStorage的重要一环,是一种轻量级NOSQL数据库.相较之下,WebDataBase标 ...
- Hibernate查询_HQL_EJBQL_QBC_QBE
查询按功能强弱可以分为以下几种:Native SQL > HQL > EJBQL > QBC > QBE 1.Native SQLNative SQL为数据库系统本身的SQL, ...