Volley Source code Analysis (vi) The dispute between--hurlstack and Httpclientstack

Source: Internet
Author: User
Tags response code

There are two ways to load a network in volley, Hurlstack and Httpclientstack, and we'll look at a piece of code in Volley.java

if (stack = = null) {//If there is no qualifying stack if            (Build.VERSION.SDK_INT >= 9) {//ADK version at 9 or above                stack = new Hurlstack ();            } else {                //Prior to Gingerbread, httpurlconnection is unreliable.                see:http://android-developers.blogspot.com/2011/09/androids-http-clients.html                stack = new HttpClientStack ( Androidhttpclient.newinstance (useragent));            }        }

Thus, if the stack is not set, it is automatically selected according to the current ADK version. Prior to the Android 2.2 version, HttpClient had fewer bugs, so using it was the best option.

HttpURLConnection is the best choice for Android version 2.3 and beyond. Its API is simple and small in size, making it ideal for Android projects. Compression and caching mechanisms can effectively reduce network access to traffic, in terms of speed and power saving also played a big role. The new application should be more inclined to use httpurlconnection, because in future work we will also spend more time on the optimization httpurlconnection.

To do this, we need to look at these two classes separately, before we look at these two, we first look at them a simple parent class Httpstack

/** * An HTTP stack abstraction. * Abstract HTTP Stack */public interface httpstack {    /**     * Performs an HTTP request with the given parameters.     * Based on parameters, execute HTTP request     * <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>< c5/>*     * @param request the request to perform     * @param additionalheaders Additional headers-be sent together WI Th     *         {@link request#getheaders ()}     * @return The HTTP response */public    HttpResponse Performrequest (request<?> Request, map<string, string> additionalheaders)        throws IOException, Authfailureerror;}

The parent class essentially stipulates that the subclass must have a method that requests data based on request and returns the HttpResponse class


OK, Next we look at Hurlstack, this class is using httpurlconnection as a connection, in the ADK higher version recommended (in fact, the market currently 2.3 of the system has been very rarely seen)

We look directly at the core method of this class Performrequest ()

@Override public HttpResponse performrequest (request<?> Request, map<string, string> additionalheaders)        Throws IOException, authfailureerror {String url = request.geturl ();        hashmap<string, string> map = new hashmap<string, string> ();        Map.putall (Request.getheaders ());        Map.putall (additionalheaders);            if (murlrewriter! = null) {String rewritten = Murlrewriter.rewriteurl (URL);            if (rewritten = = null) {throw new IOException ("URL blocked by rewriter:" + URL);        } URL = rewritten;        } URL parsedurl = new URL (URL); HttpURLConnection connection = OpenConnection (parsedurl, request);//Open connection for (String HeaderName:map.keySet ()) {//        Add request parameter Connection.addrequestproperty (Headername, Map.get (headername)); } setconnectionparametersforrequest (connection, request);//Set the requested mode//Initialize HttpResponse with the data from The HttpURLConnection. ProtocolVersion protocolversion = new ProtocolVersion ("HTTP", 1, 1);//http protocol int responsecode = CONNECTION.GETRESPO Nsecode ();//Gets the response status if (Responsecode = =-1) {//-1 Description is not responding, throws an exception//-1 is returned by Getresponsecode () if th            E response code could not being retrieved.            Signal to the caller that something is wrong with the connection.        throw new IOException ("Could not retrieve response code from HttpURLConnection."); } statusline responsestatus = new Basicstatusline (ProtocolVersion, Connection.getresponsecode (), con        Nection.getresponsemessage ());//Response Status class basichttpresponse response = new Basichttpresponse (responsestatus);  Response.setentity (Entityfromconnection (connection));//Parse Response entity for (entry<string, list<string>> header:  Connection.getheaderfields (). EntrySet ()) {//Add response header if (header.getkey () = null) {Header h = new Basicheader (HEADER.GEtkey (), Header.getvalue (). Get (0));            Response.AddHeader (h);    }} return response; }

The whole method is divided into several steps, the first of which is to store the request parameters in the map

hashmap<string, string> map = new hashmap<string, string> ();        Map.putall (Request.getheaders ());        Map.putall (additionalheaders);

Then open the URL connection

URL parsedurl = new URL (URL);        HttpURLConnection connection = OpenConnection (parsedurl, request);//Open connection
See OpenConnection () method

/** * Opens a {@link httpurlconnection} with parameters. * Open Network connection * @param URL * @return an open connection * @throws IOException */Private httpurlconnection O penconnection (URL url, request<?> Request) throws IOException {httpurlconnection connection = Createconnecti        On (URL);        int TIMEOUTMS = REQUEST.GETTIMEOUTMS ();        Connection.setconnecttimeout (TIMEOUTMS);        Connection.setreadtimeout (TIMEOUTMS);        Connection.setusecaches (FALSE);        Connection.setdoinput (TRUE); Use caller-provided custom sslsocketfactory, if any, for HTTPS if ("https". Equals (Url.getprotocol ()) &&        Msslsocketfactory! = null) {//https ((httpsurlconnection) connection). Setsslsocketfactory (Msslsocketfactory);    } return connection; }/**     * Create a {@link httpurlconnection} for the specified {@code Url}.   &nbs P */    protected HttpURLConnection createconnection (URL url) throws IOException {        return (httpurlconnection) Url.openconnection ();   }
This method essentially calls Url.openconnevtion () to return a HttpURLConnection object, where some timeout settings are provided by the request itself.

Also set setsslsocketfactory for HttpURLConnection (Msslsocketfactory objects are passed in the constructor method), depending on whether the URL has https

If you get httpurlconnection, set the request parameters

For (String HeaderName:map.keySet ()) {//Add request parameter            connection.addrequestproperty (Headername, Map.get (Headername));        }
Then determine how the request is (get,post or something else)

Setconnectionparametersforrequest (connection, request);//Set the requested mode
Setconnectionparametersforrequest Method:
@SuppressWarnings ("deprecation")/** * Set Request method * @param connection * @param request * @throws Ioexceptio n * @throws authfailureerror */* Package */static void Setconnectionparametersforrequest (Httpurlconnecti On connection, request<?> Request) throws IOException, authfailureerror {switch (request.getmetho D ()) {case Method.deprecated_get_or_post://This is the DEPRECATED-on-the-needs to be handle                D for backwards compatibility.  If the request ' s post body is null, then the assumption is, and the request is/GET.                Otherwise, it is assumed and the request is a POST.                byte[] Postbody = Request.getpostbody (); if (postbody! = null) {//Prepare output. There is no need to set content-length explicitly,//Since the is handled by HttpURLConnection using The size of the prepared//OUTPUT stream.                    Connection.setdooutput (TRUE);                    Connection.setrequestmethod ("POST");                    Connection.addrequestproperty (Header_content_type, Request.getpostbodycontenttype ());                    DataOutputStream out = new DataOutputStream (Connection.getoutputstream ());                    Out.write (Postbody);                Out.close ();            } break;                Case Method.get://Does necessary to set the request Method because connection defaults to GET                Being explicit here.                Connection.setrequestmethod ("GET");            Break                Case Method.DELETE:connection.setRequestMethod ("DELETE");            Break                Case Method.POST:connection.setRequestMethod ("POST");                Addbodyifexists (connection, request);            Break Case Method.PUT:conneCtion.setrequestmethod ("PUT");                Addbodyifexists (connection, request);            Break                Case Method.HEAD:connection.setRequestMethod ("HEAD");            Break                Case Method.OPTIONS:connection.setRequestMethod ("OPTIONS");            Break                Case Method.TRACE:connection.setRequestMethod ("TRACE");            Break                Case Method.PATCH:connection.setRequestMethod ("PATCH");                Addbodyifexists (connection, request);            Break        Default:throw new IllegalStateException ("Unknown method type."); }    }

Finally gets the response, wraps the response header information into a Statusline object, and then wraps it into a Basichttpresponse object

Statusline responsestatus = new Basicstatusline (protocolversion,                connection.getresponsecode (), Connection.getresponsemessage ());//Response Status class        Basichttpresponse response = new Basichttpresponse (responsestatus);

Then add the response content for Basichttpresponse

Response.setentity (Entityfromconnection (connection));//Parse Response entity
Entityfromconnection (HttpURLConnection Connection) method:
/**     * Initializes a {@link httpentity} from the given {@link httpurlconnection}.     * <br> Parse out response entity     * @param connection     * @return An httpentity populated with data from <CODE>CONNECTION&L T;/code>.     *    /private static httpentity entityfromconnection (HttpURLConnection connection) {        basichttpentity entity = new Basichttpentity ();        InputStream InputStream;        try {            InputStream = Connection.getinputstream ();        } catch (IOException IoE) {            InputStream = Connection.geterrorstream ();        }        Entity.setcontent (InputStream);        Entity.setcontentlength (Connection.getcontentlength ());        Entity.setcontentencoding (Connection.getcontentencoding ());        Entity.setcontenttype (Connection.getcontenttype ());        return entity;    }
Finally, add the response header content

For (entry<string, list<string>> header:connection.getHeaderFields (). EntrySet ()) {//Add response header            if ( Header.getkey () = null) {                Header h = new Basicheader (Header.getkey (), Header.getvalue (). Get (0));                Response.AddHeader (h);            }        }
OK, this returns a HttpResponse object with complete information. The whole process is relatively simple and is a regular network request content.


Next we look at the realization of Httpclientstack

Also, look directly at the Performrequest () method

@Override public    HttpResponse performrequest (request<?> Request, map<string, string> Additionalheaders)            throws IOException, Authfailureerror {        httpurirequest HttpRequest = Createhttprequest ( request, additionalheaders);        Addheaders (HttpRequest, additionalheaders);//Add Cache header        Addheaders (HttpRequest, Request.getheaders ());//Add request Header        onpreparerequest (HttpRequest);//Request preprocessing        Httpparams httpparams = Httprequest.getparams ();        int TIMEOUTMS = Request.gettimeoutms ();        Todo:reevaluate This connection timeout based on + Wide-scale        //data collection and possibly different for wif I vs. 3G.        Httpconnectionparams.setconnectiontimeout (Httpparams,);        Httpconnectionparams.setsotimeout (Httpparams, TIMEOUTMS);        Return Mclient.execute (HttpRequest);    }

The request step, first of all, according to the request method, constructs the Httpurirequest object, and sets the request parameter

Httpurirequest HttpRequest = createhttprequest (request, additionalheaders);
Createhttprequest () Method:
/** * Creates the appropriate subclass of Httpurirequest for passed in request. * Returns the subclass of the corresponding Httpurirequest */@SuppressWarnings ("deprecation")/*/protected */static Httpurirequest Crea according to the request method        Tehttprequest (request<?> Request, map<string, string> additionalheaders) throws Authfailureerror { Switch (Request.getmethod ()) {case method.deprecated_get_or_post: {//This is the Depre                cated-On-the-needs to is handled for backwards compatibility.  If the request ' s post body is null, then the assumption is, and the request is/GET.                Otherwise, it is assumed and 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);//Set the requested parameter return postrequest;                } case method.put: {httpput putrequest = new Httpput (Request.geturl ());                Putrequest.addheader (Header_content_type, Request.getbodycontenttype ());                Setentityifnonemptybody (putrequest, request); Return PUtrequest;            } Case Method.HEAD:return New Httphead (Request.geturl ());            Case Method.OPTIONS:return New Httpoptions (Request.geturl ());            Case Method.TRACE:return New HttpTrace (Request.geturl ());                Case Method.patch: {httppatch patchrequest = new Httppatch (Request.geturl ());                Patchrequest.addheader (Header_content_type, Request.getbodycontenttype ());                Setentityifnonemptybody (patchrequest, request);            return patchrequest;        } Default:throw New IllegalStateException ("Unknown request method."); }    }
As can be seen from the Createhttprequest () method, in HttpClient, as long as the request method, the new one httpget/httppost/.... The object is ready (and urlstack This step is really connnection)

The request header is then set for the Httpurirequest object

Addheaders (HttpRequest, additionalheaders);//Add Cache header        Addheaders (HttpRequest, Request.getheaders ());//Add request Header
Addheaders Method:
/**     * Add response header     * @param httprequest     * @param headers * * *    private static void Addheaders (Httpurirequest HttpRequest, map<string, string> headers) {for        (String Key:headers.keySet ()) {            Httprequest.setheader ( Key, Headers.get (key));        }    }
Finally, the Httpurirequest object is handed to httpclient for execution

Return Mclient.execute (HttpRequest);

Ok,httpclientstack is simpler than we thought, at least simpler than hurlstack, which is of course, because the httpclient approach is essentially the encapsulation of the URLConnection, but the package is not perfect, So the differences between versions are caused.


To this end, we introduce the two classes of Hurlstack and Httpclientstack, and also illustrate where real network requests are performed.

Next article will come to understand the use of response<t>,response<t> is volley the entire process, the final goal, as a response entity, we look at how response<t> is designed.


Volley Source code Analysis (vi) The dispute between--hurlstack and Httpclientstack

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.