Volley source code Analysis (II.) Introduction of--request<t> class

Source: Internet
Author: User
Tags sha1 encryption sha1 hash

In the previous article, we have mentioned the use of volley and design of the overall idea, from this article, I will be combined with specific source code to show you the specific implementation of volley functions.

The first class we're going to introduce is request<t>, an abstract class, which I call a request that inherits request<t> to customize the request and provides a more flexible interface for volley.

The generic T in request<t> refers to the result after parsing response. As we know in the previous article, Responsedelivery will assign the response to the corresponding request (the Chinese translation is to assign the response to the corresponding requests). In our defined request, we need to rewrite the parsenetworkresponse (networkresponse response) method, parse the request, parse the result, is the T type.

OK, let's look directly at the source code.

First, there are some properties

/** * Base class for all network requests. * Request base class * @param <T> the type of parsed response this request expects. * T for response type */public abstract class Request<t> implements comparable<request<t>> {/** * Default enc Oding for POST or PUT parameters.     See {@link #getParamsEncoding ()}.    * Default code */private static final String default_params_encoding = "UTF-8";     /** * Supported request methods.        * Supported Request method */public interface Method {int deprecated_get_or_post =-1;        int GET = 0;        int POST = 1;        int PUT = 2;        int DELETE = 3;        int HEAD = 4;        int OPTIONS = 5;        int TRACE = 6;    int PATCH = 7; }/** * An event log tracing the lifetime of this request;     For debugging. * For tracking the lifetime of the request, for debugging * */private final Markerlog Meventlog = markerlog.enabled?    New Markerlog (): null;  /** * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,     * TRACE, and PATCH.    * Current Request Method */private final int mmethod;      /** * URL of this request.        * Request Address */private final String Murl;    /** * The redirect URL to use for 3xx HTTP responses * REDIRECT Address */private String Mredirecturl;    /** * The unique identifier of the request * * * private String midentifier;     /** * Default tag for {@link trafficstats}.    * Traffic Statistics TAB */private final int mdefaulttrafficstatstag;     /** * Listener interface for errors.    * ERROR Listener */private final response.errorlistener Merrorlistener;     /** * Sequence Number of this request, used to enforce FIFO ordering.    * Request sequence number, for FIFO algorithm */private Integer msequence;     /** * The request queue this request was associated with.    * Request Queue * */private requestqueue mrequestqueue;     /** * Whether or not responses to this request should be cached. * Whether to use cached response requests */private boolEan Mshouldcache = true;     /** * Whether or not this request has been canceled.    * Whether the request was canceled */private Boolean mcanceled = false;     /** * Whether or not a response have been delivered for this request yet.        * Whether the request has been answered */private Boolean mresponsedelivered = false;     /** * A Cheap variant of request tracing used to dump slow requests.    * A simple variable, tracking request, used to discard slow requests * request generation time */private long mrequestbirthtime = 0; /** Threshold at which we should logs the request (even when debug logging was not enabled).    */private static final long Slow_request_threshold_ms = 3000;     /** * The retry policy for this request.    * Request Retry Policy */private retrypolicy mretrypolicy;  /** * When a request can is retrieved from cache but must is refreshed from * The network, the cache entry would be     Stored here's in the event of * a "not Modified" response, we can be sure it hasn ' t been evicted from cache. * Cache records. When a request is available from the cacheWhen the response is received, but must be updated from the network.     We keep this cache record so that once the response from the network is not Modified * (no update), the cache is not recycled.    */private Cache.entry mcacheentry = null; /** * Opaque token tagging this request;     Used for bulk cancellation. * Used for custom tags, can be understood as the classification used for requests */private Object Mtag;
It has to be said that there are so many properties (I write comments), but each property has its own usefulness, and some of the properties are set up that we are not very likely to consider. I'd like to introduce you.

1,default_params_encoding = "UTF-8" default encoding

2,mmethod Request method

3,murl Request Address

4,mredirecturl redirect address, this address will be used when the network response status code is 403

5,msequence serial number, which is the sequence number (not the order) of this request in the queue

The request queue where the 6,mrequestqueue request is located

7,merrorlistener Error Listener

If the 9,mshouldcache is cached, if this property is true, the view will first query the request result from the cache

10,mcacheentry Cache record, this record is used to cache the response first

11,mtag custom tags, the user can give some request custom tags, using these tags, we can uniformly manage the requests for these tokens, such as unified cancellation of them


Next look at the construction method

/**     * Creates a new request with the given method (one of the values from {@link method}),     * URL, and Error listen Er.  Note that the normal response listener isn't provided here     as * Delivery of responses are provided by subclasses There is a better idea of what to deliver     * an already-parsed response.     * Create a new request (requires address, error listener, etc.) */Public request    (int method, String URL, Response.errorlistener listener) According to the requested method {        Mmethod = method;        Murl = URL;        Midentifier = Createidentifier (method, URL);//create unique credentials for the request        Merrorlistener = listener;//Set listener        setretrypolicy ( New Defaultretrypolicy ());//Set Default Retry policy        mdefaulttrafficstatstag = Finddefaulttrafficstatstag (URL);//Set Traffic flag    }
The first is the request method, the setting of the request address, which is required as a request. Then is the listener settings, note here is just this is the Errorlistner, stating that Errorlistener is necessary, but the correct response, we may not handle. This setting is reasonable, because the error, we have to deal with, as to the success of the request, we can not deal with. So what do we want to do with a successful request, which requires overriding the constructor in the subclass (for example, Stringrequest).

Then you create a unique credential.

/**     *  SHA1 (Request:method:url:timestamp:counter)     * @param method http method     * @param URL               http Request URL     * @return SHA1 hash string     * SHA1 encryption using the requested method and address, creating a unique credential for the request */    private static string Createidentifier (final int method, final String URL) {        return Internalutils.sha1hash ("Request:" + method + ":" + URL +                ":" + system.currenttimemillis () + ":" + (scounter++));    }
As can be seen from the above method, this voucher is related to the current time and is therefore unique

Then set the retry policy, this class, and so on, followed by the traffic flag setting, the so-called traffic flag, is used for debug logging, not the focus

/**     * @return The hashcode of the URL ' s host component, or 0 if there is none.     * Returns the hashcode of the host address portion of the URL, if host does not exist, returns 0     *    /private static int finddefaulttrafficstatstag (String URL) {        if (! Textutils.isempty (URL)) {            uri uri = uri.parse (URL);            if (uri! = null) {                String host = Uri.gethost ();                if (host! = null) {                    return host.hashcode ()                ;        }}} return 0;    }

Let's go back and look at this retry strategy.

Volley has specifically defined a class for the retry strategy, so that we can implement our own retries policy as needed, and for the internal source, we provide a default retry policy defaultretrypolicy ()

To introduce the retry strategy, we first value the base class of the trial strategy Retrypolicy

/** * Retry policy for a request. * Request retry Policy class */public interface Retrypolicy {    /**     * Returns The current timeout (used for logging).     * Get current time, for log     *    /public int getcurrenttimeout ();    /**     * Returns the current retry count (used for logging).     * Returns the current number of retries for log     *    /public int getcurrentretrycount ();    /**     * Prepares for the next retry by applying a backoff to the timeout.     * @param error The error code of the last attempt.     * @throws Volleyerror in the event that the retry could is not being performed (for example if we     * ran out of attempts), T He passed in error is thrown.     * Retry Implementation     *    /public void retry (Volleyerror error) throws Volleyerror;}
The important thing is retry () This method, we look at defaultretrypolicy inside the concrete implementation of this method

/**     * Prepares for the next retry by applying a backoff to the timeout.     * @param error The error code of the last attempt.     *    /@Override public    void Retry (volleyerror error) throws Volleyerror {        mcurrentretrycount++;//current retry count        Mcurrenttimeoutms + = (MCURRENTTIMEOUTMS * mbackoffmultiplier);//Current out of time        if (!hasattemptremaining ()) {// Whether the maximum number of retries has been reached            throw error;        }    }    /** * Returns True if this policy has attempts remaining, false otherwise.     * If also retry */protected Boolean hasattemptremaining () {return mcurrentretrycount <= mmaxnumretries;//Maximum retry count }
As you can see, in the default retry policy, only the number of retries is simply counted, and then the exception is thrown after the maximum number of times has been exceeded.

It's that simple, so how does the volley try again?

In fact, when a request is taken out of the queue to make a requests for a network, we are writing in a dead loop (which can be seen later in the code so that it does not bother to overload the class).

Once the request fails, it calls the Retry () method above, but does not jump out of the loop. Return only if the request succeeds in obtaining response. If the request fails all the time, according to the retry policy above, the Volleyerror exception is thrown, and the exception is not handled, but instead is thrown out by throws, thus ending the dead loop.

From a programming point of view, by throwing an exception to the end of the dead loop, it is not so elegant (usually we end the loop with the method of setting the tag), but in the volley, the reason is that for this exception, to the programmer to do their own processing, although this makes the process of exception passing complicated, However, the flexibility of the program is increased.

The final exception, which we will deal with in Request<t> 's Parsenetworkerror () and Delivererror () methods, Parsenetworkerror () is used to parse Volleyerror, The Delivererror () method recalls the Errorlistener mentioned above at the beginning.

    /** * Subclasses can override this method to parse ' Networkerror ' and return a more specific error. * * <p>the Default implementation just returns the passed ' Networkerror ' .</p> * * @param volleyerr     The or the error retrieved from the network * @return a networkerror augmented with additional information * Resolves a networking error    */Public Volleyerror parsenetworkerror (Volleyerror volleyerror) {return volleyerror; }/**     * delivers error message to the Errorlistener, the Request was   &nbsp ; * Initialized with.     *     * @param error Error details   & nbsp * Distribution network error      */    public void Delivererror (volleyerror error) {         if (Merrorlistener! = null) {             Merrorlistener.onerrorresponse (Error);       }   } 
In fact, in addition to the above two methods of handling errors, there are two methods to handle a successful response, it is necessary to inherit the

/**     * Subclasses must implement this to parse the RAW network response     * and return an appropriate response type. This method would be is     * called from a worker thread.  The response is not being delivered     * if you return null.     * @param response response from the network     * @return The parsed response, or null in the case of an error     * Parse response c8/>*/public    abstract response<t> parsenetworkresponse (Networkresponse Response); <pre name= "Code" Class= "java" >/**     * Subclasses must implement this to perform delivery of the parsed     * response to their Liste Ners.  The given response is guaranteed to     * was non-null; responses that fail to parse was not delivered.     * @param response The parsed response returned by     * {@link #parseNetworkResponse (networkresponse)}     * Distribution response     *    /public abstract void Deliverresponse (T response);


Parsenetworkresponse (networkresponse response) is used to resolve the network response to local response, the parsed response, will be given to Deliverresponse (T Response) method.

Why to parse, actually said above, to parse the result into the T type. As for these two methods, they are actually called in the Responsedelivery response dispatcher.

After reading the initialization method, we look at the end of the request method, finish (), sometimes we want to actively terminate the request, for example, stop downloading the file, or the request has been successful, we remove the request from the queue

/** * Notifies the request queue that this request has finished (successfully or with error). * Reminder request queue, current request completed (failed or successful) * <p>also dumps all events from this request ' s event log;            For debugging.</p> * * */public void finish (final String tag) {if (mrequestqueue! = null) {  Mrequestqueue.finish (this);//The request is completed} if (markerlog.enabled) {//If debug final long threadId =                Thread.CurrentThread (). GetId ();//thread ID if (looper.mylooper ()! = Looper.getmainlooper ()) {//Request not in main thread If we finish marking off of the main thread, we need to//actually does it on the main thread to Ensu            Re correct ordering.                If we do not record log on the main thread, we need to do this work on the main thread to ensure the correct order Handler Mainthread = new Handler (Looper.getmainlooper ());                        Mainthread.post (New Runnable () {@Override public void run () {    Meventlog.add (tag, threadId);                    Meventlog.finish (This.tostring ());                }                });            Return            }//If the main thread, directly record Meventlog.add (tag, threadId);        Meventlog.finish (This.tostring ());            } else {//does not turn on debug long RequestTime = Systemclock.elapsedrealtime ()-mrequestbirthtime;            if (requesttime >= Slow_request_threshold_ms) {volleylog.d ("%d MS:%s", RequestTime, This.tostring ()); }        }    }

The main thing is to do some logging work, the most important thing is to call the Mrequestqueue's finish () method, to remove the request from the queue.


After reading the above introduction, do you notice that,request<t> inherited the Comparable<request<t>> interface, why to inherit this interface, we certainly want to see CompareTo () method

/**     * Our comparator sorts-from-low-priority, and secondarily by     * Sequence number to provide FIFO Orderin G.     *    /@Override public    int CompareTo (request<t> other) {priority Left        = This.getpriority ();        Priority right = Other.getpriority ();        High-priority Requests is "lesser" so they is sorted to the front.        Equal priorities is sorted by sequence number to provide FIFO ordering.        return left = = right?                This.msequence-other.msequence:                right.ordinal ()-left.ordinal ();    }
This method compares the priority of two requests, and, if the precedence is equal, in order

The purpose of implementing this interface, as mentioned in the previous article, is that some of the requests are more important and want to be executed earlier, that is, let it be ahead of the request queue

By comparing methods, we can set the basis for the order in which requests are queued in the request queue, so that the precedence is high.


Ok,request<t> Basic Introduction, of course, some properties, such as cache Mcacheentry,mredirecturl redirect address and so we have not used, we first remember them, will be used in the future.

In fact, the Request<t> class is not complex, mainly is the setting of some properties, some of these properties are more difficult to consider, such as priority, redirect address, custom tags, retry policy and so on.


Finally, we look at the concrete implementation of the Request<t> class through Stringrequest

/** * A canned request for retrieving the response body at a given URL as a String. */public class Stringrequest extends request<string> {    private final listener<string> Mlistener;    /**     * Creates a new request with the given method.     *     * @param method The request {@link method} to use     * @param URL URL for fetch the string at     * @param listener Listener to receive the String response     * @param errorlistener Error Listener, or null to ignore errors     */    Pub LIC stringrequest (int method, String URL, listener<string> Listener,            errorlistener errorlistener) {        Super (method, URL, errorlistener);        Mlistener = listener;    }

In the above construction method, a new interface listener<string> listener was added to monitor the successful response

And then Parsenetworkresponse (networkresponse response), this method

@Overridepublic response<string> parsenetworkresponse (networkresponse Response) {        String parsed;        try {            parsed = new String (Response.data, Httpheaderparser.parsecharset (response.headers));        } catch ( Unsupportedencodingexception e) {            parsed = new String (response.data);        }        Return response.success (parsed, httpheaderparser.parsecacheheaders (Response));    }
As you can see, the networkresponse is parsed into a string type and then constructed into the corresponding local response

@Overridepublic void Deliverresponse (String response) {        mlistener.onresponse (response);    }
As for Deliverresponse (String response), a new listener is called that is required in the constructor method.


So far, the introduction to request<t> is over, and since the coupling of request<t> and other classes is not particularly heavy, I believe it is easier to understand.

In the next article, we'll look at the requestqueue queue and see what this queue does, why we create a queue to hold the request instead of just opening a thread to each request to load the network data.



Volley source code Analysis (II.) Introduction of--request<t> class

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.