zoukankan      html  css  js  c++  java
  • volley介绍07

    -------------------------------------------------------------------------------

    转载:http://blog.csdn.net/crazy__chen/article/details/46610461

    -------------------------------------------------------------------------------

    Volley中网络加载有两种方式,分别是HurlStack与HttpClientStack,我们来看Volley.java中的一段代码

    [java] view plain copy
     
    1. if (stack == null) {//如果没有限定stack  
    2.             if (Build.VERSION.SDK_INT >= 9) {//adk版本在9或者以上  
    3.                 stack = new HurlStack();  
    4.             } else {  
    5.                 // Prior to Gingerbread, HttpUrlConnection was unreliable.  
    6.                 // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html  
    7.                 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  
    8.             }  
    9.         }  


    由此可见,如果没有设置stack,则根据当前adk版本自动选择。在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。

    而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。

    为此,我们需要分别来看这两个类,在看这两个之前,我们先来看它们一个简单的父类HttpStack

    [java] view plain copy
     
    1. /** 
    2.  * An HTTP stack abstraction. 
    3.  * 抽象的http栈 
    4.  */  
    5. public interface HttpStack {  
    6.     /** 
    7.      * Performs an HTTP request with the given parameters. 
    8.      * 根据参数,执行http请求 
    9.      * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, 
    10.      * and the Content-Type header is set to request.getPostBodyContentType().</p> 
    11.      * 
    12.      * @param request the request to perform 
    13.      * @param additionalHeaders additional headers to be sent together with 
    14.      *         {@link Request#getHeaders()} 
    15.      * @return the HTTP response 
    16.      */  
    17.     public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)  
    18.         throws IOException, AuthFailureError;  
    19.   
    20. }  


    该父类主要规定了,子类必须有一个根据request请求数据,并且返回HttpResponse类的方法

    OK,接下来我们先看HurlStack,这个类使用的是HttpURLConnection作为连接方式,在adk较高版本推荐使用(其实目前市场上2.3的系统已经很少见了)

    我们直接看这个类的核心方法performRequest()

    [java] view plain copy
     
    1. @Override  
    2.     public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)  
    3.             throws IOException, AuthFailureError {  
    4.         String url = request.getUrl();  
    5.         HashMap<String, String> map = new HashMap<String, String>();  
    6.         map.putAll(request.getHeaders());  
    7.         map.putAll(additionalHeaders);  
    8.         if (mUrlRewriter != null) {  
    9.             String rewritten = mUrlRewriter.rewriteUrl(url);  
    10.             if (rewritten == null) {  
    11.                 throw new IOException("URL blocked by rewriter: " + url);  
    12.             }  
    13.             url = rewritten;  
    14.         }  
    15.         URL parsedUrl = new URL(url);  
    16.         HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接  
    17.         for (String headerName : map.keySet()) {//添加请求参数  
    18.             connection.addRequestProperty(headerName, map.get(headerName));  
    19.         }  
    20.         setConnectionParametersForRequest(connection, request);//设置请求方式  
    21.         // Initialize HttpResponse with data from the HttpURLConnection.  
    22.         ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);//http协议  
    23.         int responseCode = connection.getResponseCode();//获取响应状态  
    24.         if (responseCode == -1) {//-1说明没有响应,抛出异常  
    25.             // -1 is returned by getResponseCode() if the response code could not be retrieved.  
    26.             // Signal to the caller that something was wrong with the connection.  
    27.             throw new IOException("Could not retrieve response code from HttpUrlConnection.");  
    28.         }  
    29.         StatusLine responseStatus = new BasicStatusLine(protocolVersion,  
    30.                 connection.getResponseCode(), connection.getResponseMessage());//响应状态类  
    31.         BasicHttpResponse response = new BasicHttpResponse(responseStatus);  
    32.         response.setEntity(entityFromConnection(connection));//解析响应实体  
    33.         for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头  
    34.             if (header.getKey() != null) {  
    35.                 Header h = new BasicHeader(header.getKey(), header.getValue().get(0));  
    36.                 response.addHeader(h);  
    37.             }  
    38.         }  
    39.         return response;  
    40.     }  


    整个方法分成几个步骤,首先是将请求参数,存储到map当中

    [java] view plain copy
     
    1. HashMap<String, String> map = new HashMap<String, String>();  
    2.        map.putAll(request.getHeaders());  
    3.        map.putAll(additionalHeaders);  

    然后是开启url连接

    [java] view plain copy
     
    1. URL parsedUrl = new URL(url);  
    2.         HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接  

    来看openConnection()方法

    [java] view plain copy
     
    1. /** 
    2.      * Opens an {@link HttpURLConnection} with parameters. 
    3.      * 开启网络连接 
    4.      * @param url 
    5.      * @return an open connection 
    6.      * @throws IOException 
    7.      */  
    8.     private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {  
    9.         HttpURLConnection connection = createConnection(url);  
    10.   
    11.         int timeoutMs = request.getTimeoutMs();  
    12.         connection.setConnectTimeout(timeoutMs);  
    13.         connection.setReadTimeout(timeoutMs);  
    14.         connection.setUseCaches(false);  
    15.         connection.setDoInput(true);  
    16.   
    17.         // use caller-provided custom SslSocketFactory, if any, for HTTPS  
    18.         if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {//https  
    19.             ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);  
    20.         }  
    21.   
    22.         return connection;  
    23.     }  
    24.   
    25.    /** 
    26.      * Create an {@link HttpURLConnection} for the specified {@code url}. 
    27.      */  
    28.     protected HttpURLConnection createConnection(URL url) throws IOException {  
    29.         return (HttpURLConnection) url.openConnection();  
    30.     }  

    这个方法主要就是调用url.openConnevtion()从而返回一个HttpURLConnection对象,其中的一些超时设置,是由request本身提供的

    另外还根据url是否带有https,为HttpURLConnection设置setSSLSocketFactory(mSslSocketFactory对象是在构造方法中传入的)

    得到HttpURLConnection,就设置请求参数

    [java] view plain copy
     
    1. for (String headerName : map.keySet()) {//添加请求参数  
    2.             connection.addRequestProperty(headerName, map.get(headerName));  
    3.         }  

    然后是确定请求方式(GET,POST还是别的)

    [java] view plain copy
     
    1. setConnectionParametersForRequest(connection, request);//设置请求方式  

    setConnectionParametersForRequest方法:

    [java] view plain copy
     
    1. @SuppressWarnings("deprecation")  
    2.     /** 
    3.      * 设置请求方式 
    4.      * @param connection 
    5.      * @param request 
    6.      * @throws IOException 
    7.      * @throws AuthFailureError 
    8.      */  
    9.     /* package */   
    10.     static void setConnectionParametersForRequest(HttpURLConnection connection,  
    11.             Request<?> request) throws IOException, AuthFailureError {  
    12.         switch (request.getMethod()) {  
    13.             case Method.DEPRECATED_GET_OR_POST:  
    14.                 // This is the deprecated way that needs to be handled for backwards compatibility.  
    15.                 // If the request's post body is null, then the assumption is that the request is  
    16.                 // GET.  Otherwise, it is assumed that the request is a POST.  
    17.                 byte[] postBody = request.getPostBody();  
    18.                 if (postBody != null) {  
    19.                     // Prepare output. There is no need to set Content-Length explicitly,  
    20.                     // since this is handled by HttpURLConnection using the size of the prepared  
    21.                     // output stream.  
    22.                     connection.setDoOutput(true);  
    23.                     connection.setRequestMethod("POST");  
    24.                     connection.addRequestProperty(HEADER_CONTENT_TYPE,  
    25.                             request.getPostBodyContentType());  
    26.                     DataOutputStream out = new DataOutputStream(connection.getOutputStream());  
    27.                     out.write(postBody);  
    28.                     out.close();  
    29.                 }  
    30.                 break;  
    31.             case Method.GET:  
    32.                 // Not necessary to set the request method because connection defaults to GET but  
    33.                 // being explicit here.  
    34.                 connection.setRequestMethod("GET");  
    35.                 break;  
    36.             case Method.DELETE:  
    37.                 connection.setRequestMethod("DELETE");  
    38.                 break;  
    39.             case Method.POST:  
    40.                 connection.setRequestMethod("POST");  
    41.                 addBodyIfExists(connection, request);  
    42.                 break;  
    43.             case Method.PUT:  
    44.                 connection.setRequestMethod("PUT");  
    45.                 addBodyIfExists(connection, request);  
    46.                 break;  
    47.             case Method.HEAD:  
    48.                 connection.setRequestMethod("HEAD");  
    49.                 break;  
    50.             case Method.OPTIONS:  
    51.                 connection.setRequestMethod("OPTIONS");  
    52.                 break;  
    53.             case Method.TRACE:  
    54.                 connection.setRequestMethod("TRACE");  
    55.                 break;  
    56.             case Method.PATCH:  
    57.                 connection.setRequestMethod("PATCH");  
    58.                 addBodyIfExists(connection, request);  
    59.                 break;  
    60.             default:  
    61.                 throw new IllegalStateException("Unknown method type.");  
    62.         }  
    63.     }  

    最后获取响应,将响应头信息包装成StatusLine对象,再包装成BasicHttpResponse对象

    [java] view plain copy
     
    1. StatusLine responseStatus = new BasicStatusLine(protocolVersion,  
    2.                 connection.getResponseCode(), connection.getResponseMessage());//响应状态类  
    3.         BasicHttpResponse response = new BasicHttpResponse(responseStatus);  


    然后为BasicHttpResponse加入响应内容

    [java] view plain copy
     
    1. response.setEntity(entityFromConnection(connection));//解析响应实体  

    entityFromConnection(HttpURLConnection connection)方法:

    [java] view plain copy
     
    1. /** 
    2.      * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}. 
    3.      * <br>解析出响应实体 
    4.      * @param connection 
    5.      * @return an HttpEntity populated with data from <code>connection</code>. 
    6.      */  
    7.     private static HttpEntity entityFromConnection(HttpURLConnection connection) {  
    8.         BasicHttpEntity entity = new BasicHttpEntity();  
    9.         InputStream inputStream;  
    10.         try {  
    11.             inputStream = connection.getInputStream();  
    12.         } catch (IOException ioe) {  
    13.             inputStream = connection.getErrorStream();  
    14.         }  
    15.         entity.setContent(inputStream);  
    16.         entity.setContentLength(connection.getContentLength());  
    17.         entity.setContentEncoding(connection.getContentEncoding());  
    18.         entity.setContentType(connection.getContentType());  
    19.         return entity;  
    20.     }  

    最后,加入响应头部内容

    [java] view plain copy
     
    1. for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头  
    2.             if (header.getKey() != null) {  
    3.                 Header h = new BasicHeader(header.getKey(), header.getValue().get(0));  
    4.                 response.addHeader(h);  
    5.             }  
    6.         }  

    OK,这样就返回了一个具有完整信息的HttpResponse对象。整个过程比较简单,是常规的网络请求内容。

    接下来我们看HttpClientStack的实现

    同样,直接来看performRequest()方法

    [java] view plain copy
     
    1. @Override  
    2.     public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)  
    3.             throws IOException, AuthFailureError {  
    4.         HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);  
    5.         addHeaders(httpRequest, additionalHeaders);//添加缓存头  
    6.         addHeaders(httpRequest, request.getHeaders());//添加请求头  
    7.         onPrepareRequest(httpRequest);//请求预处理  
    8.         HttpParams httpParams = httpRequest.getParams();  
    9.         int timeoutMs = request.getTimeoutMs();  
    10.         // TODO: Reevaluate this connection timeout based on more wide-scale  
    11.         // data collection and possibly different for wifi vs. 3G.  
    12.         HttpConnectionParams.setConnectionTimeout(httpParams, 5000);  
    13.         HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);  
    14.         return mClient.execute(httpRequest);  
    15.     }  


    请求步骤,首先是根据请求方式,构造HttpUriRequest对象,并且设置请求参数

    [java] view plain copy
     
    1. HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);  

    createHttpRequest()方法:

    [java] view plain copy
     
    1. /** 
    2.      * Creates the appropriate subclass of HttpUriRequest for passed in request. 
    3.      * 根据请求方式返回对应HttpUriRequest的子类 
    4.      */  
    5.     @SuppressWarnings("deprecation")  
    6.     /* protected */   
    7.     static HttpUriRequest createHttpRequest(Request<?> request,  
    8.             Map<String, String> additionalHeaders) throws AuthFailureError {  
    9.         switch (request.getMethod()) {  
    10.             case Method.DEPRECATED_GET_OR_POST: {  
    11.                 // This is the deprecated way that needs to be handled for backwards compatibility.  
    12.                 // If the request's post body is null, then the assumption is that the request is  
    13.                 // GET.  Otherwise, it is assumed that the request is a POST.  
    14.                 byte[] postBody = request.getPostBody();  
    15.                 if (postBody != null) {  
    16.                     HttpPost postRequest = new HttpPost(request.getUrl());  
    17.                     postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());  
    18.                     HttpEntity entity;  
    19.                     entity = new ByteArrayEntity(postBody);  
    20.                     postRequest.setEntity(entity);  
    21.                     return postRequest;  
    22.                 } else {  
    23.                     return new HttpGet(request.getUrl());  
    24.                 }  
    25.             }  
    26.             case Method.GET:  
    27.                 return new HttpGet(request.getUrl());  
    28.             case Method.DELETE:  
    29.                 return new HttpDelete(request.getUrl());  
    30.             case Method.POST: {  
    31.                 HttpPost postRequest = new HttpPost(request.getUrl());  
    32.                 postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
    33.                 setEntityIfNonEmptyBody(postRequest, request);//设置请求参数  
    34.                 return postRequest;  
    35.             }  
    36.             case Method.PUT: {  
    37.                 HttpPut putRequest = new HttpPut(request.getUrl());  
    38.                 putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
    39.                 setEntityIfNonEmptyBody(putRequest, request);  
    40.                 return putRequest;  
    41.             }  
    42.             case Method.HEAD:  
    43.                 return new HttpHead(request.getUrl());  
    44.             case Method.OPTIONS:  
    45.                 return new HttpOptions(request.getUrl());  
    46.             case Method.TRACE:  
    47.                 return new HttpTrace(request.getUrl());  
    48.             case Method.PATCH: {  
    49.                 HttpPatch patchRequest = new HttpPatch(request.getUrl());  
    50.                 patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
    51.                 setEntityIfNonEmptyBody(patchRequest, request);  
    52.                 return patchRequest;  
    53.             }  
    54.             default:  
    55.                 throw new IllegalStateException("Unknown request method.");  
    56.         }  
    57.     }  

    从createHttpRequest()方法可以看出,在HttpClient中,只要根据请求方式,new一个HttpGet/HttpPost/....对象就可以了(而urlstack这一步是真的connnection而言的)

    接着是为HttpUriRequest对象设置请求头部

    [java] view plain copy
     
    1. addHeaders(httpRequest, additionalHeaders);//添加缓存头  
    2.        addHeaders(httpRequest, request.getHeaders());//添加请求头  

    addHeaders方法:

    [java] view plain copy
     
    1. /** 
    2.      * 添加响应头 
    3.      * @param httpRequest 
    4.      * @param headers 
    5.      */  
    6.     private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {  
    7.         for (String key : headers.keySet()) {  
    8.             httpRequest.setHeader(key, headers.get(key));  
    9.         }  
    10.     }  

    最后,将HttpUriRequest对象交给httpClient执行

    [java] view plain copy
     
    1. return mClient.execute(httpRequest);  

    OK,HttpClientStack比我们想象的还要简单,起码比HurlStack简单,这是当然的,因为使用httpClient方式,其本质就是对urlConnection的封装,然而这个封装并不是很完美,所以造成了版本之间的差异。

    到此为止,给大家介绍了HurlStack与HttpClientStack这两个类,同时也说明了真正的网络请求在哪里执行。

    下一篇文章,将会来了解Response<T>的使用,Response<T>是Volley整个过程中,辗转获得的最终目的,作为响应实体,我们来看一下Response<T>是怎么设计的。

  • 相关阅读:
    对象遍历 for in ,数组遍历for in 与 for of 的区别
    计算一个数组中key值相同的数量
    VUE的两种跳转push和replace对比区别
    微信公众号二次分享ios分享失败问题
    获得对象中的键或值
    第一个table根据checkbox选择tr,在另一个table中显示对应索引的tr(jq遍历的运用)
    checkbox 全选反选 获得所有的checkbox
    为什么jQuery要return this.each()?
    用jq代码写出一个轮播图。
    页面滚动到一定位置,两个div 朝中间运动。
  • 原文地址:https://www.cnblogs.com/aprz512/p/5316739.html
Copyright © 2011-2022 走看看