RTFSC-Android volley

Android-volley

Volley擅长执行用来显示UI的RPC操作

使用时注意事项

  • 别忘了添加到请求队列中

流程解析

使用Volley.newRequestQueue新建请求队列

// 新建一个请求队列,使用Volley.newRequestQueue(Context)
RequestQueue requestQueue = Volley.newRequestQueue(this);
// 或
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());

例子:建立 JsonObjectRequest ,并添加到请求队列中

首先看 JsonObjectRequest 的继承关系,按照这个关系来解析流程

public class JsonObjectRequest extends JsonRequest<JSONObject>
    public abstract class JsonRequest<T> extends Request<T>
        public abstract class Request<T> implements Comparable<Request<T>>

新建JsonObjectRequest实例时,使用JsonRequest.java的构造方法(也可将此看做API):
(String url, JSONObject/JSON对象/, Listener / 监听器/, ErrorListener / 错误监听器/)
如果JSON对象为null,则默认参数为Method.GET

    /**
 * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
 * <code>null</code>, <code>POST</code> otherwise.
 *
 * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener)
 */
    public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
            ErrorListener errorListener) {
        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
                listener, errorListener);
    }

跳转到JsonObjectRequest.java中的构造方法:

    /**
 * Creates a new request.
 * @param method the HTTP method to use
 * @param url URL to fetch the JSON from
 * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and
 * indicates no parameters will be posted along with request.
 * @param listener Listener to receive the JSON response
 * @param errorListener Error listener, or null to ignore errors.
 */
    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
            Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                errorListener);
    }

按照继承关系,再跳到JsonRequest.java中:

    public JsonRequest(int method, String url, String requestBody, Listener<T> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
        mRequestBody = requestBody;
    }

    // listener 请求回传数据
    @Override
    protected void deliverResponse(T response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

    // requestBody 获取字节
    // PROTOCOL_CHARSET = "utf-8"
    @Override
    public byte[] getBody() {
        try {
            return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
        } catch (UnsupportedEncodingException uee) {
            VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
                    mRequestBody, PROTOCOL_CHARSET);
            return null;
        }
    }

method, url, errorListener传入到Request.java中:

    /**
 * Creates a new request with the given method (one of the values from {@link Method}),
 * URL, and error listener. Note that the normal response listener is not provided here as
 * delivery of responses is provided by subclasses, who have a better idea of how to deliver
 * an already-parsed response.
 */
    public Request(int method, String url, Response.ErrorListener listener) {
        mMethod = method;
        mUrl = url;
        mIdentifier = createIdentifier(method, url);
        mErrorListener = listener;
        setRetryPolicy(new DefaultRetryPolicy());// 默认设定

        mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
    }

/* Request 使用默认的设定;
 /**
 * Constructs a new retry policy using the default timeouts.
 */
    public DefaultRetryPolicy() {
        this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
    }
*/

    // 产生ID
    private static String createIdentifier(final int method, final String url) {
        return InternalUtils.sha1Hash("Request:" + method + ":" + url +
                ":" + System.currentTimeMillis() + ":" + (sCounter++));
    }

一个JsonObjectRequest实例创建好,传给请求队列 requestQueue
requestQueue.add(jsonRequest);/* add to request queue */
在add方法中,判断 request 是否能被cache化,不能被cache化直接添加进 mNetworkQueue
如果能被cache化,取得 request 的 key,查看是否需要排队
不用排队的,加入 mCacheQueue;当前队列有请求在排队,则排在后面 mWaitingRequests
把 mCacheQueue, mNetworkQueue 一起加入
RequestQueue.java


    /**
 * The set of all requests currently being processed by this RequestQueue. A Request
 * will be in this set if it is waiting in any queue or currently being processed by
 * any dispatcher.
 */
    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

    /** The cache triage queue. */
    private final PriorityBlockingQueue<Request<?>> mCacheQueue =
        new PriorityBlockingQueue<Request<?>>();

    /** The queue of requests that are actually going out to the network. */
    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
        new PriorityBlockingQueue<Request<?>>();

    // 存放request
    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

    /**
 * Adds a Request to the dispatch queue.
 * @param request The request to service
 * @return The passed-in request
 */
    public <T> Request<T> add(Request<T> request) {
        // Tag the request as belonging to this queue and add it to the set of current requests.
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // Process requests in the order they are added.
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");

        // If the request is uncacheable, skip the cache queue and go straight to the network.
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
        }

        // Insert request into stage if there's already a request with the same cache key in flight.
        synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();// 获取 请求的 key
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);// 等待队列
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);// 需要排队的
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);// 当前已无排队的请求
                mCacheQueue.add(request);// 加入队列中
            }
            return request;
        }
    }

    // 启动
    /**
 * Starts the dispatchers in this queue.
 */
    public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // Create the cache dispatcher and start it.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();// 启动线程

        // Create network dispatchers (and corresponding threads) up to the pool size.
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

CacheDispatcher 启动线程来进行下载;CacheDispatcher.java

public class CacheDispatcher extends Thread

    ......

    /**
 * Creates a new cache triage dispatcher thread. You must call {@link #start()}
 * in order to begin processing.
 *
 * @param cacheQueue Queue of incoming requests for triage
 * @param networkQueue Queue to post requests that require network to
 * @param cache Cache interface to use for resolution
 * @param delivery Delivery interface to use for posting responses
 */
    public CacheDispatcher(
            BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
            Cache cache, ResponseDelivery delivery) {
        mCacheQueue = cacheQueue;
        mNetworkQueue = networkQueue;
        mCache = cache;
        mDelivery = delivery;
    }

    // 在复写的run方法中,有一个while(true)循环执行下载
    @Override
    public void run() {
        ......
        Request<?> request;
        while (true) {
            // release previous request object to avoid leaking request object when mQueue is drained.
            request = null;
            try {
                // Take a request from the queue.
                request = mCacheQueue.take();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }
            try {
                ......

                // We have a cache hit; parse its data for delivery back to the request.
                request.addMarker("cache-hit");
                Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");

                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    mDelivery.postResponse(request, response);
                } else {
                    // Soft-expired cache hit. We can deliver the cached response,
                    // but we need to also send the request to the network for
                    // refreshing.
                    request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);

                    // Mark the response as intermediate.
                    response.intermediate = true;

                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    final Request<?> finalRequest = request;
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(finalRequest);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
            }
        }
    }

你可能感兴趣的:(RTFSC-Android volley)