teach you how to distribute and execute HTTP requests for Android network framework

Source: Internet
Author: User
Tags response code


Objective

In the first two blogs of the "teach you to write Android network framework" column, we have introduced the basic structure of the simplenet framework, as well as the implementation of request, Response, requests queue, and why design What is the consideration of this design? The first two blogs have introduced the various roles, and today we are going to dissect several other particularly important roles, namely Networkexecutor, Httpstack, and responsedelivery, which correspond to the function of the network request thread, HTTP executor, response distribution, these three are the core of executing HTTP request and processing response.

Let's look back and simplenet the roles of each other. First, the user needs to create a request queue and then add individual requests to the request queue. Multiple networkexecutor (essentially a thread) share a message queue, loop requests in the fetch request queue in each networkexecutor, get a request, and then execute an HTTP request through Httpstack. After the request is completed, the response results are eventually distributed to the UI thread through Responsedelivery, ensuring that the request callback is executed on the UI thread so that the user can update the UI directly in the callback. Execution Process 1.


Figure 1

There are also the first blogs in the reference column that are not quite familiar with this architecture diagram.

Networkexecutor

As the "Heart" in Simplenet,Networkexecutor plays a very important role. It is called "heart" because the function of Networkexecutor is to continuously fetch requests from the request queue and then hand it to Httpstack to execute. It is like the engine in the car, the heart of the human body, driving the entire framework of the operation.

Networkexecutor is essentially a thread, in the Run method we will execute a loop, constantly get requests from the request queue, and then to Httpstack, because the simpler we directly on the code bar.

/** * Network Request executor, inherits from Thread, loops the request from the network request queue and executes * * @author mrsimple */final class Networkexecutor extends Thread {/*    * * Network Request queue */private blockingqueue<request<?>> mrequestqueue;    /** * Network Request stack */private httpstack mhttpstack;    /** * Result Dispatcher, post the result to the main thread */private static Responsedelivery Mresponsedelivery = new Responsedelivery ();    /** * Request Cache */private static cache<string, response> Mreqcache = new Lrumemcache ();    /** * Whether to stop */private Boolean isstop = false;        Public Networkexecutor (blockingqueue<request<?>> queue, Httpstack httpstack) {mrequestqueue = queue;    Mhttpstack = Httpstack; } @Override public void Run () {try {while (!isstop) {final request<?> requ                EST = mrequestqueue.take ();                    if (request.iscanceled ()) {LOG.D ("# # #", "# # # Cancel Execution");                Continue           }     Response Response = null;                if (Isusecache (Request)) {//from cache response = Mreqcache.get (Request.geturl ());                    } else {//Get data from the network response = mhttpstack.performrequest (request); If the request requires caching, then the request is cached to Mresponsecache if (Request.shouldcache () && issuccess (r                    Esponse)) {Mreqcache.put (Request.geturl (), response);            }}//Distribution Request Results Mresponsedelivery.deliveryresponse (request, response);        }} catch (Interruptedexception e) {log.i ("", "# # # Request Dispatcher exit"); }} Private Boolean issuccess (Response Response) {return Response! = null && Response.getstatuscode (    ) = = 200; } Private Boolean Isusecache (Request<?> Request) {return Request.shouldcache () && Mreqcache.get (r Equest.geturl ())! = nulL        } public void Quit () {isstop = true;    Interrupt (); }}
When the request queue is started, we start the specified number ofNetworkexecutor (refer to the request for writing Android network framework, the response class and the requests queue)。 In the constructionNetworkexecutor will inject the request queue and httpstack into it, so that Networkexecutor has two elements, the request queue and the Httpstack. The request is then continuously fetched in the loop of the run function and given to Httpstack, which also determines whether the request needs to be cached, whether it already has a cache, if the cache is used, and if it already contains the cache, then the cached results are used. execute the HTTP request in the run function so that the network request is executed in the child thread. Executing HTTP requires Httpstack, but in the end we need to distribute the results to the UI thread, which requires responsedelivery, which we'll cover here.


Httpstack

Httpstack is just an interface, only one the Performrequest function, which is the execution request.

/** * Interface to perform network requests *  * @author mrsimple */public interface Httpstack {    /**     * Execute HTTP request     *      * @param request Pending Request     * @return *     /public    Response performrequest (request<?> request);}

Httpstack is the real performer of the network request, with Httpclientstack and Httpurlconnstack, The two are Apache HttpClient and Java httpurlconnection, for the difference between the two please refer to:Android access to the network, using HttpURLConnection or httpclient? By default, we build the corresponding Httpstack based on the API version, and of course the user can implement a httpstack on their own, and then pass in the Simplenet factory function.

For example:

    /**     * @param corenums thread core number     * @param httpstack http Executor *    /protected requestqueue (int corenums, Httpstack httpstack) {        mdispatchernums = corenums;        Mhttpstack = Httpstack! = null? HttpStack:HttpStackFactory.createHttpStack ();    }
Httpstack is passed when the request queue is acquired, and if Httpstack is empty, the corresponding Httpstack is generated by httpstackfactory based on the API version. That is, API 9 below is Httpclientstack, API 9 and above is Httpurlconnstack.
/** * Based on API version Select HttpClient or HttpURLConnection *  @author mrsimple */public final class Httpstackfactory {    private static final int gingerbread_sdk_num = 9;    /**     * Create a different HTTP executor based on the SDK version number, that is, use httpclient before SDK 9, then use Httlurlconnection,     * Please refer to the difference between the two:     */http android-developers.blogspot.com/2011/09/androids-http-clients.html     *      * @return */public    static Httpstack Createhttpstack () {        int runtimesdkapi = Build.VERSION.SDK_INT;        if (Runtimesdkapi >= gingerbread_sdk_num) {            return new httpurlconnstack ();        }        return new Httpclientstack ();}    }

Httpclientstack and Httpurlconnstack respectively encapsulate HTTP requests for httpclient and HttpURLConnection, build requests, set headers, set request parameters, Parse response and other operations. For this layer, we do not give an abstract class, because HttpClient and httpurlconnection do not belong to the same class family, their behavior is similar, but some of the types involved are different. Here we give an example of Httpurlconnstack, recently busy, so the configuration is relatively simple to write, the students need to optimize their own.

/** * Use HttpURLConnection to perform network requests Httpstack * * @author mrsimple */public class Httpurlconnstack implements Httpstack {    /** * Configure HTTPS */httpurlconnconfig Mconfig = Httpurlconnconfig.getconfig ();        @Override public Response performrequest (request<?> Request) {httpurlconnection urlconnection = null;            try {//build httpurlconnection URLConnection = Createurlconnection (Request.geturl ());            Set Headers setrequestheaders (URLConnection, request);            Set body parameter Setrequestparams (urlconnection, request);            HTTPS configuration Confighttps (request);        Return Fetchresponse (URLConnection);        } catch (Exception e) {e.printstacktrace ();            } finally {if (urlconnection! = null) {urlconnection.disconnect ();    }} return null;     } private httpurlconnection createurlconnection (String url) throws IOException {   URL newurl = new URL (URL);        URLConnection urlconnection = Newurl.openconnection ();        Urlconnection.setconnecttimeout (mconfig.conntimeout);        Urlconnection.setreadtimeout (mconfig.sotimeout);        Urlconnection.setdoinput (TRUE);        Urlconnection.setusecaches (FALSE);    Return (httpurlconnection) URLConnection; } private void Confighttps (request<?> Request) {if (Request.ishttps ()) {sslsocketfactory SslF            Actory = Mconfig.getsslsocketfactory ();                Configure HTTPS if (sslfactory! = null) {httpsurlconnection.setdefaultsslsocketfactory (sslfactory);            Httpsurlconnection.setdefaulthostnameverifier (Mconfig.gethostnameverifier ()); }}} private void Setrequestheaders (httpurlconnection connection, request<?> Request) {set<        string> Headerskeys = Request.getheaders (). KeySet (); for (String Headername:headerskeys) {CONNECTION.ADDREQUESTPROperty (Headername, Request.getheaders (). Get (Headername)); }} protected void Setrequestparams (httpurlconnection connection, request<?> Request) throws Protoc        Olexception, IOException {HttpMethod method = Request.gethttpmethod ();        Connection.setrequestmethod (Method.tostring ());        Add params byte[] BODY = request.getbody ();            if (BODY = null) {//Enable output connection.setdooutput (TRUE); Set content type connection. Addrequestproperty (Request.header_content_type, REQUEST.GETB            Odycontenttype ()); Write params data to connection DataOutputStream DataOutputStream = new DataOutputStream (CONNECTION.GETOUTPU            TStream ());            Dataoutputstream.write (body);        Dataoutputstream.close (); }} private Response Fetchresponse (httpurlconnection connection) throws IOException {//Initialize HTTPRESPO NSE with data from The HttpURLConnection.        ProtocolVersion protocolversion = new ProtocolVersion ("HTTP", 1, 1);        int responsecode = Connection.getresponsecode ();        if (Responsecode = =-1) {throw new IOException ("Could not retrieve response code from HttpURLConnection."); }//Status line data statusline responsestatus = new Basicstatusline (protocolversion, connection.        Getresponsecode (), Connection.getresponsemessage ());        Build Response Response Response = new Response (responsestatus);        Set response Data response.setentity (Entityfromurlconnwction (connection));        Addheaderstoresponse (response, connection);    return response; /** * gets to its data stream after executing an HTTP request, that is, the stream that returns the result of the request * * @param connection * @return */private httpentity Entit        Yfromurlconnwction (httpurlconnection connection) {basichttpentity entity = new basichttpentity ();        InputStream inputstream = null; try {inputstReam = Connection.getinputstream ();            } catch (IOException e) {e.printstacktrace ();        InputStream = Connection.geterrorstream ();        }//Todo:gzip entity.setcontent (InputStream);        Entity.setcontentlength (Connection.getcontentlength ());        Entity.setcontentencoding (Connection.getcontentencoding ());        Entity.setcontenttype (Connection.getcontenttype ());    return entity; } private void Addheaderstoresponse (basichttpresponse response, httpurlconnection connection) {for (entry<st                 Ring, List<string>> Header:connection.getHeaderFields (). EntrySet ()) {if (Header.getkey ()! = null) {                Header h = new Basicheader (Header.getkey (), Header.getvalue (). Get (0));            Response.AddHeader (h); }        }    }}
The code is simple enough to say.

Responsedelivery

In Httpstack's performrequest function, we return a response object that contains the corresponding response we requested. About the response class you don't know much about the request, response class, and requests queue that teaches you to write the Android network framework. The final step in executing the HTTP request in Networkexecutor is to distribute the results to the UI thread, and the main task is to execute the requested callback to the UI thread so that the user can update the UI, among other things.

    @Override public void Run () {try {while (!isstop) {final request<?> Reque                st = Mrequestqueue.take ();                    if (request.iscanceled ()) {LOG.D ("# # #", "# # # Cancel Execution");                Continue                } Response Response = null;                if (Isusecache (Request)) {//from cache response = Mreqcache.get (Request.geturl ());                    } else {//Get data from the network response = mhttpstack.performrequest (request); If the request requires caching, then the request is cached to Mresponsecache if (Request.shouldcache () && issuccess (r                    Esponse)) {Mreqcache.put (Request.geturl (), response);            }}//Distribution Request Results Mresponsedelivery.deliveryresponse (request, response); }} catch (Interruptedexception e) {log.i ("", "# # # Requests(the sender exits "); }    }
We get a response object either from the cache or from the network, and finally we distribute the results to the UI thread through the Responsedelivery object.

Responsedelivery actually encapsulates the handler that is associated with the UI thread message queue, and in the Deliveryresponse function executes the deliveryresponse of the request in the UI thread. Now that we have the handler object associated with the UI thread, build a runnable directly, and execute the deliveryresponse function of the request in that runnable. In Deliveryresponse of the REquest class, the Parseresponse parsing response result is also called, and the result type returned is T in Request<t>, which is specified in the request subclass. For example Jsonrequest, the result of the returned response is Jsonobject. This way we get the JSON data returned by the server and pass the JSON result to the UI thread in the form of a callback. The user can update the UI in the callback.

This is mainly abstract and generic, writing the framework is often a very important means of generics, so familiarity with the use of abstractions and generics is an important step in object-oriented development.

The Responsedelivery code is as follows:

/** * Request result drop class, POST request result to UI thread *  * @author mrsimple */class Responsedelivery implements Executor {    /**     * Main thread hand ER     */    Handler Mresponsehandler = new Handler (Looper.getmainlooper ());    /**     * Processes the request result, executes it on the UI thread     *      * @param request     * @param response    */public void Deliveryresponse (Final request<?> Request, final Response Response) {        Runnable resprunnable = new Runnable () {            @Override public            void Run () {                request.deliveryresponse (response);            }        };        Execute (resprunnable);    }    @Override public    void execute (Runnable command) {        mresponsehandler.post (command);}    }

The Deliveryresponse function of the request class.

    /**     * Handles response, the method runs on the UI thread.     *      * @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);        }    }

In this way, the entire request process is complete. Let's summarize the process below.

the data format returned by different users ' servers is inconsistent, so we have defined the request<t> generic base class, which is the type of data format returned by generic T. For example, the returned data format is JSON, the corresponding request is jsonrequest, the generic T is Jsonobject, in the jsonrequest overwrite the parseresponse function, Converts the original data in the resulting response into jsonobject. The request is then placed in the queue, networkexecutor the request to httpstack execution, the response object is obtained after execution completes, and the result is Responsedelivery posted to the UI thread via the request callback.

GitHub links

Https://github.com/bboyfeiyu/simple_net_framework



teach you how to distribute and execute HTTP requests for Android network framework

Related Article

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.