Teach you to write the request, response class, and requests queue for the Android network framework

Source: Internet
Author: User

Reprint Please indicate the source, this article from "Mr.simple's blog".

I am participating in the blog star, click here to vote for me, thank you ~

Objective

Teaching you to write the basic architecture of the Android network framework we have introduced the basic structure of the Simplenet network framework, and today we start from the point of view of the code to begin to cut into the implementation of the network framework, in the analysis of the same time we will analyze the design ideas, and why to do so, What is the benefit of doing this? So we not only learned how to implement the network framework, but also learned to design a common framework should be considered, which extends to the scope of framework design, through this simple example hope to give new people some help. Of course, this is only opinion, we can have their own ideas of implementation.

As you can see, this series of blogs is prepared for the newcomers, if you are a master, please ignore.

In framework development, it is important to abstract. That is, an important principle in object-oriented: the dependency inversion principle, which is simply to rely on abstraction, and not rely on concrete. This makes our framework extensible and also satisfies the open and closed principle of opening up to extensions and closing the modifications. The most important abstraction for our network framework is the Reqeust class, the response class, so today we start with two classes. Finally we introduce the request queue (Requestqueue) in the network framework, which is the central nervous in the simplenet, and all requests need to be placed in the queue and then wait to be executed. The request queue is like a pipeline in a factory, and a network request is like a product to be processed on an assembly line. The object executing the network request is similar to the workers in the factory, waiting for the product to be passed on the assembly line in their own position, then processing it and putting the product in other position. Their role mapping reference figure 1, such as some of the roles of simplenet are not clear can be referred to teach you to write the basic framework of the Android Network article.

Figure 1


Request Class

Since the network framework, let's start with the network request class first. As has been said earlier, since it is a framework, it requires extensibility. Therefore the request is destined to be abstract rather than concrete. And for the network request, the user gets the request result format is indeterminate, for example some server returned is JSON, some returned is the XML, some directly is the string. But for HTTP response, its return data type is stream, which means that the raw data we get is a binary stream. So in the request base class we must reserve the method to parse the specific type returned by the response, although the returned types are different, but their processing logic is the same, so we can use request as a generic class whose generic type is its return data type, such as the request <string>, then its return data type is of type String. There is also the priority of the request, can be canceled, and so on, we first give the core code, and then continue to analyze.

/** * Network Request class. Note that get and delete cannot pass the request parameter because of the nature of the request, and the user can build the parameter into the URL and pass it into the request. * * @author mrsimple * @param <T> T The data type returned for the request */public abstract class Request<t> implements Comparable<req uest<t>> {/** * HTTP request Method Enumeration, here we only get, POST, PUT, delete four kinds * * @author mrsimple * * Public        static enum HttpMethod {get ("get"), post ("Post"), put ("put"), delete ("delete");        /** HTTP Request type */private String Mhttpmethod = "";        Private HttpMethod (String method) {Mhttpmethod = method;        } @Override Public String toString () {return mhttpmethod;         }}/** * Precedence enumeration * * @author Mrsimple */public static enum-priority {low, NORMAL, Hign, IMMEDIATE}/** * Default encoding for POST or PUT parameters.     See * {@link #getParamsEncoding ()}. */private static final String default_params_encoding = "UTF-8";    /** * Request Serial number */protected int mserialnum = 0;    /** * Priority is set to NORMAL */protected mpriority = Priority.normal;    /** * Whether to cancel the request */protected Boolean iscancel = false;    /** whether the request should be cached */private Boolean mshouldcache = true;    /** * Request Listener */protected requestlistener<t> Mrequestlistener;    /** * Requested URL */private String Murl = "";    /** * Request Method */HttpMethod Mhttpmethod = Httpmethod.get;    /** * Request Header */private map<string, string> mheaders = new hashmap<string, string> ();    /** * Request Parameters */Private map<string, string> mbodyparams = new hashmap<string, string> (); /** * @param method * @param URL * @param listener */Public Request (HttpMethod method, String URL, Req        Uestlistener<t> listener) {Mhttpmethod = method;        Murl = URL;    Mrequestlistener = listener; }/** * Parse result from native network request, subclass overwrite *      * @param response * @return * */public abstract T parseresponse (response response);     /** * Handles response, the method runs on the UI thread. * * @param response */public final void Deliveryresponse (response response) {//Parse GET request result T Res        Ult = 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);    }} public String GetUrl () {return murl;    } public int Getserialnumber () {return mserialnum;    } public void Setserialnumber (int mserialnum) {this.mserialnum = Mserialnum;    } Public Priority getpriority () {return mpriority;    } public void SetPriority (priority mpriority) {this.mpriority = mpriority; } protected String getparamsencoding () {return default_params_enCODING; } public String Getbodycontenttype () {return ' application/x-www-form-urlencoded;    charset= "+ getparamsencoding ();    } public HttpMethod Gethttpmethod () {return mhttpmethod;    } public map<string, String> getheaders () {return mheaders;    } public map<string, String> Getparams () {return mbodyparams;    } public void Cancel () {Iscancel = true;    } public boolean isCanceled () {return iscancel;  }/** * The body parameter byte array when returning a post or put request * */public byte[] GetBody () {map<string, string> params        = Getparams ();        if (params! = null && params.size () > 0) {return encodeparameters (params, getparamsencoding ());    } return null; /** * Convert parameter to URL-encoded parameter string */private byte[] Encodeparameters (map<string, string> params, String Paramsen        Coding) {StringBuilder encodedparams = new StringBuilder (); try {For (map.entry<string, string> entry:params.entrySet ()) {Encodedparams.append (Urlencoder.encode (ent                Ry.getkey (), paramsencoding));                Encodedparams.append (' = ');                Encodedparams.append (Urlencoder.encode (Entry.getvalue (), paramsencoding));            Encodedparams.append (' & ');        } return Encodedparams.tostring (). GetBytes (paramsencoding); } catch (Unsupportedencodingexception uee) {throw new RuntimeException ("Encoding not supported:" + Paramsenco        Ding, uee); }}//is used to sort the request, sorted by priority and sequence number joined to the queue @Override public int compareTo (request<t> another) {Priorit        Y mypriority = this.getpriority ();        Priority anotherpriority = Another.getpriority (); If the priority is equal, then return Mypriority.equals (another) is performed according to the sequence of sequence numbers added to the queue.    This.getserialnumber ()-Another.getserialnumber (): Mypriority.ordinal ()-anotherpriority.ordinal (); }/** * Network request ListeNER, will be executed on UI thread * * @author mrsimple * @param <T> Requested response type */public static interface request listener<t> {/** * Request completed CALLBACK * * @param response */public void Oncomp    lete (int stcode, T response, String errmsg); }}

The code above is request<t> as an abstract class, and T is the data format that the request response. This t is a more important point in the request class, different people have different requirements, that is, the request reponse data format is not all the same, we must take into account the multiplicity of request return type, using generic T to represent the returned data format type, The request subclass then writes the corresponding method to parse the response data format, and finally calls the request listener to execute the request result on the UI thread so that the entire demand is complete.

each request has a serial number, which is generated by the request queue and identifies the sequence number of the request in the queue, which determines the order in which the request is ordered in the queue, that is, its execution in the request queue. Each request has a request method, such as "POST", "GET", where we use enumerations instead, named types are easier to use than simple strings. Each request can be added with header, body parameters (the format of the request parameters can refer to four common POST-submission data methods), and can be canceled. Abstract classes encapsulate common code, only the mutable ones are abstract functions, and only parseresponse this function.

For example, the data format we return is JSON, so we build a subclass called Jsonrequest, the sample code is as follows.

/** * The data type returned is a JSON request, the JSON corresponds to the object type Jsonobject *  * @author mrsimple */public class Jsonrequest extends Request<json object> {public    jsonrequest (HttpMethod method, String URL, requestlistener<jsonobject> listener) {        Super (method, URL, listener);    }        /**     * Convert the results of Response to Jsonobject     *    /@Override public    jsonobject parseresponse (Response Response) {        string jsonstring = new String (Response.getrawdata ());        try {            return new Jsonobject (jsonstring),        } catch (Jsonexception e) {            e.printstacktrace ();        }        return null;}    }

As you can see, implementing a request class is very simple and requires only a overwriteparseresponse function to parse the data returned by your request. This guarantees scalability, such as later if I want to use this framework to do a imageloader, then I can create a imagerequest, the type of the request returned is bitmap, then we only need to overwrite the parseresponse function, Then convert the results into bitmap.

The response class is introduced here, the response class stores the requested status code, request results, and so on, we continue to look down.

Response class

Each request corresponds to a response, but the problem here is that this response data format is unknown to us. We're writing a framework, not an application. The framework just constructs a basic environment and comes with some more commonly used classes, such as the jsonrequest here. But the important point is to allow the user to expand freely and simply to achieve his needs. For the response class, the most important thing for us is to determine the data format type of the request result. As we all know, HTTP is actually based on the TCP protocol, and the TCP protocol is based on Socket,socket actually operation is the input, output stream, the output stream is to write data to the server, the input stream is naturally read data from the server. So we should use InputStream to store the results in the response class or use an easier-to-use byte array, where we use byte arrays to store them. Let's look at the response class.

/** * Request result class, inherit from Basichttpresponse, store the result in RawData.    * @author mrsimple */public class Response extends Basichttpresponse {public byte[] RawData = new Byte[0];    Public Response (Statusline statusline) {super (statusline);    } public Response (ProtocolVersion ver, int code, String reason) {super (ver, code, reason);        } @Override public void setentity (httpentity entity) {super.setentity (entity);    RawData = Entitytobytes (GetEntity ());    } public byte[] Getrawdata () {return rawdata;    } public int Getstatuscode () {return Getstatusline (). Getstatuscode ();    Public String GetMessage () {return Getstatusline (). Getreasonphrase (); }/** Reads the contents of httpentity into a byte[].        */Private byte[] Entitytobytes (httpentity entity) {try {return Entityutils.tobytearray (entity);        } catch (IOException e) {e.printstacktrace ();    } return new byte[0]; }}

This class is very simple, just inherit the Basichttpresponse, and then convert the input stream into a byte array, and then wrap a few common methods, mainly for the use of simple bar. We store the result as a byte array, so that users can easily convert the results to string, bitmap and other data types, if the direct storage is inputstream, then in many cases the user needs to be inputstream in the periphery into a byte array, It is then converted to the final format, such as InputStream to string type. This is why we choose byte[] instead of InputStream.


Request queue

the network request queue is also relatively simple, in effect, it encapsulates a priority queue that, when the queue is built, initiates several networkexecutor (child threads) to fetch requests from the request queue and execute the request. The request queue is sorted according to the priority of the request, which ensures that some high-priority requests are processed as quickly as possible, which is why the comparable interface is implemented in the request class. If the priority is consistent, it is sorted according to the order in which the request is added to the queue, which is generated by the request queue, which guarantees the same precedence as the policy in FIFO.

/** * Request queue, use priority queue, so that requests can be processed by priority. [Thread Safe] * * @author mrsimple */public final class Requestqueue {/** * request queue [Thread-safe] */priv    Ate blockingqueue<request<?>> mrequestqueue = new priorityblockingqueue<request<?>> ();    /** * Requested serialization generator */private Atomicinteger mserialnumgenerator = new Atomicinteger (0);    /** * Default number of cores */public static int default_core_nums = Runtime.getruntime (). Availableprocessors () + 1;    /** * Number of CPU cores + 1 distribution threads */private int mdispatchernums = Default_core_nums;    /** * Networkexecutor, the thread executing the network request */private networkexecutor[] mdispatchers = null;    /** * True Performer of HTTP request */private httpstack mhttpstack; /** * @param corenums Thread Core number */protected requestqueue (int corenums, Httpstack httpstack) {Mdispatchernu        ms = Corenums; Mhttpstack = Httpstack! = null?    HttpStack:HttpStackFactory.createHttpStack ();  }/** * Start Networkexecutor   */private final void Startnetworkexecutors () {mdispatchers = new networkexecutor[mdispatchernums]; for (int i = 0; i < mdispatchernums; i++) {mdispatchers[i] = new Networkexecutor (Mrequestqueue, Mhttpstack)            ;        Mdispatchers[i].start ();        }} public void Start () {Stop ();    Startnetworkexecutors (); }/** * Stop networkexecutor */public void Stop () {if (mdispatchers! = null && mdispatchers.le            Ngth > 0) {for (int i = 0; i < mdispatchers.length; i++) {mdispatchers[i].quit (); }}}/** * cannot repeat add request * * @param request */public void addrequest (request<?>             Request) {if (!mrequestqueue.contains (Request)) {Request.setserialnumber (This.generateserialnumber ());        Mrequestqueue.add (Request);        } else {log.d ("", "# # # Request queue already contains"); }} public void Clear () {MREquestqueue.clear ();    } public blockingqueue<request<?>> getallrequests () {return mrequestqueue; /** * Generates a serial number for each request * * @return Sequence number */private int generateserialnumber () {return MSERIALN    Umgenerator.incrementandget (); }}

This introduces a httpstack, which is an interface with only one function. This interface defines the abstraction for executing a network request with the following code:

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

Come here today, the introduction of Httpstack, Networkexecutor, Responsedelivery will be updated in the next blog, please look forward to.


GitHub Address

Simplenet Network Framework Address

Teach you to write the request, response class, and requests queue for the Android network framework

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.