Android中的volley_4_执行网络请求的接口Network及其实现类BasicNetwork

来源:互联网 发布:淘宝开店需要押金吗 编辑:程序博客网 时间:2024/06/05 20:54


demo下载:http://download.csdn.net/detail/vvzhouruifeng/8747599


在volley中执行网络请求的接口是Network,其实现类是BasicNetwork。

需要注意的是,将Network与HttpStack、HttpClientStack 、HurlStack进行区别。HttpStack是定义网络请求的,是使用HttpClient或者HttpURLConnection来连接网络。Network则是使用HttpStack来执行网络请求。

Network接口内定义了一个唯一的方法public NetworkResponse performRequest(Request<?> request)   其作用就是执行网络请求,并获取返回值。

/** * An interface for performing requests. * 调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。 *  * 代表网络的接口,处理网络请求。 唯一的方法,用于执行特定请求 */public interface Network {/** * Performs the specified request. 执行网络请求,获取一个从网络后返回的响应 ,BasicNetwork是该接口的实现类 *  * @param request *            Request to process * @return A {@link NetworkResponse} with data and caching metadata; will *         never be null  NetworkResponse是响应数据,该数据是根据从缓存获得或从网络中获取的响应数据封装起来的 * @throws VolleyError *             on errors */public NetworkResponse performRequest(Request<?> request)throws VolleyError;}

Network是一个接口,volley中该接口的默认实现类是BasicNetwork。

BasicNetwork具体执行了网络请求,它有这么几个作用:

1.在构造的时候需要确定使用的网络请求方式,需要HttpStack的实现类,HttpClientStack 或者HurlStack
2.执行HttpStack网络请求,获取响应。
3.请求网络,如果请求失败还需要进行请求重试策略
4.解析响应,组装成可以被volley传递的NetworkResponse
5.在解析响应实体的时候,使用字节数组缓冲池技术


public class BasicNetwork implements Network {    protected static final boolean DEBUG = VolleyLog.DEBUG;    private static int SLOW_REQUEST_THRESHOLD_MS = 3000;    //默认的byte[]缓冲池的大小    private static int DEFAULT_POOL_SIZE = 4096;    //具体的执行网络请求的实例,这里使用的是接口,可以用接口的实现类HttpClientStack    HurlStack的实例    protected final HttpStack mHttpStack;    //因为大量用到byte[],考虑节省内存问题,创建了一个byte数组缓冲池    protected final ByteArrayPool mPool;    /**     * @param httpStack HTTP stack to be used     * 使用默认大小的字节数组缓冲池     *      */    public BasicNetwork(HttpStack httpStack) {        // If a pool isn't passed in, then build a small default pool that will give us a lot of        // benefit and not use too much memory.        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));    }    /**     * @param httpStack HTTP stack to be used     * @param pool a buffer pool that improves GC performance in copy operations  可以自己来定义一个缓冲池     */    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {        mHttpStack = httpStack;        mPool = pool;    }    /**     * 执行具体的网络请求 ,需要Volley的Request,返回的是可以被传递的响应     */    @Override    public NetworkResponse performRequest(Request<?> request) throws VolleyError {        long requestStart = SystemClock.elapsedRealtime();        //这里使用while(true)的含义是:保证请求重试策略的执行。        //如果网络正常返回结果 那么直接return         //如果需要进行请求重试,就用到这里了,保证了可以进行请求重试        while (true) {        //系统的网络请求的响应            HttpResponse httpResponse = null;            //存放响应实体的字节数组            byte[] responseContents = null;            //存储响应头信息的map            Map<String, String> responseHeaders = new HashMap<String, String>();            try {                // Gather headers.                Map<String, String> headers = new HashMap<String, String>();                //从request中获取一些头的信息,新鲜度验证的tag和缓存的响应的响应时间                addCacheHeaders(headers, request.getCacheEntry());                //执行请求,获得相应                httpResponse = mHttpStack.performRequest(request, headers);                //获取响应的状态行                StatusLine statusLine = httpResponse.getStatusLine();                //获取状态码                int statusCode = statusLine.getStatusCode();                //将响应的头信息转为map存储                responseHeaders = convertHeaders(httpResponse.getAllHeaders());                // Handle cache validation.  返回的状态码是304  表示可以使用缓存数据                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,                            request.getCacheEntry().data, responseHeaders, true);                }                //表示不使用缓存数据                // Some responses such as 204s do not have content.  We must check.204(无内容)服务器成功处理了请求,但没有返回任何内容                if (httpResponse.getEntity() != null) {                //响应实体不为空,使用的是响应实体的数据,获取响应的实体  转为字节数组                //这里有可能抛出IO异常,当出现异常的时候需要再下面捕获异常并进行处理,主要是完成创建可被传递的NetworkResponse                  responseContents = entityToBytes(httpResponse.getEntity());                } else {                  // Add 0 byte response as a way of honestly representing a                  // no-content request.                //表示响应实体为空,没有传回数据                  responseContents = new byte[0];                }                // if the request is slow, log it.  对于具体的业务流程,暂时没看出有什么大的影响                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;                logSlowRequests(requestLifetime, request, responseContents, statusLine);                if (statusCode < 200 || statusCode > 299) {                    throw new IOException();                }                //根据httpResponse的信息,组装成可以被volley传递的networkresponse                   //此时while循环结束                return new NetworkResponse(statusCode, responseContents, responseHeaders, false);            //如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束                //当catch后没有执行上边的return  而当前又是一个while(true)循环,可以保证下面的请求重试的执行,是利用循环进行请求重试,请求重试策略只是记录重试的次数、超时 时间等内容。            } catch (SocketTimeoutException e) {            //当出现异常的时候,尝试进行请求重试                attemptRetryOnException("socket", request, new TimeoutError());            } catch (ConnectTimeoutException e) {            //当出现异常的时候,尝试进行请求重试                attemptRetryOnException("connection", request, new TimeoutError());            } catch (MalformedURLException e) {            //url不正常异常                throw new RuntimeException("Bad URL " + request.getUrl(), e);            } catch (IOException e) {            //当出现IO异常时,在try内读取数据体时,如果出现IO异常,那么捕获异常,继续完成创建NetworkResponse的过程                int statusCode = 0;                NetworkResponse networkResponse = null;                //如果响应不为空                if (httpResponse != null) {                //获取返回的状态码                    statusCode = httpResponse.getStatusLine().getStatusCode();                } else {                //响应为空就表明 网络连接错误                    throw new NoConnectionError(e);                }                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());                if (responseContents != null) {                //根据状态码、响应的实体数、响应头信息创建可被传递的响应                    networkResponse = new NetworkResponse(statusCode, responseContents,                            responseHeaders, false);                    //如果状态码是授权未通过                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||                            statusCode == HttpStatus.SC_FORBIDDEN) {                    //请求重试策略                        attemptRetryOnException("auth",                                request, new AuthFailureError(networkResponse));                    } else {                        // TODO: Only throw ServerError for 5xx status codes.                        throw new ServerError(networkResponse);                    }                } else {                    throw new NetworkError(networkResponse);                }            }        }    }    /**     * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.     * 如果该请求的时间超过了之前设置的时间,那么log下     */    private void logSlowRequests(long requestLifetime, Request<?> request,            byte[] responseContents, StatusLine statusLine) {        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {            VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +                    "[rc=%d], [retryCount=%s]", request, requestLifetime,                    responseContents != null ? responseContents.length : "null",                    statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());        }    }    /**     * 请求重试策略     * Attempts to prepare the request for a retry. If there are no more attempts remaining in the     * request's retry policy, a timeout exception is thrown.     * @param request The request to use.     */    private static void attemptRetryOnException(String logPrefix, Request<?> request,            VolleyError exception) throws VolleyError {    //获得该请求的请求重试策略        RetryPolicy retryPolicy = request.getRetryPolicy();        //请求重试策略的超时时间        int oldTimeout = request.getTimeoutMs();        try {        //内部实现,重试次数+1  超时时间变化        //如果重试次数超过限定的最大次数,该方法抛出异常            retryPolicy.retry(exception);        } catch (VolleyError e) {        //当超过了最大重试次数,捕获到异常,给改请求添加标记 标记超时            request.addMarker(                    String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));            //抛出异常            throw e;        }        //给请求添加标记,请求了多少次        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));    }    /**     * 从volley的请求中拿到头信息     * @Description     * @param headers     * @param entry     * @date 2015年5月18日 下午2:32:06     */    private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {        // If there's no cache entry, we're done. 请求中没有实体,那么不做操作        if (entry == null) {            return;        }        //如果 Request 中带有实体信息,如 Etag,Last-Modify 等,则进行缓存新鲜度的验证        if (entry.etag != null) {            headers.put("If-None-Match", entry.etag);        }        //响应产生的时间        if (entry.serverDate > 0) {            Date refTime = new Date(entry.serverDate);            headers.put("If-Modified-Since", DateUtils.formatDate(refTime));        }    }    protected void logError(String what, String url, long start) {        long now = SystemClock.elapsedRealtime();        VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);    }    /** Reads the contents of HttpEntity into a byte[]. 将响应的数据实体转为byte[]*/    private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {    //定义输出流        PoolingByteArrayOutputStream bytes =                new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());        byte[] buffer = null;        try {            InputStream in = entity.getContent();            if (in == null) {                throw new ServerError();            }            //从byte[]缓冲池中取字节数组            buffer = mPool.getBuf(1024);            int count;            while ((count = in.read(buffer)) != -1) {                bytes.write(buffer, 0, count);//从buffer中读取内容写入输出流中的byte[]中            }            return bytes.toByteArray();        } finally {            try {                // Close the InputStream and release the resources by "consuming the content".                entity.consumeContent();            } catch (IOException e) {                // This can happen if there was an exception above that left the entity in                // an invalid state.                VolleyLog.v("Error occured when calling consumingContent");            }            //将字节数组返回到缓冲池中            mPool.returnBuf(buffer);            //关闭输出流            bytes.close();        }    }    /**     * Converts Headers[] to Map<String, String>.     * 将响应的头信息解析出来转为map格式     */    private static Map<String, String> convertHeaders(Header[] headers) {        Map<String, String> result = new HashMap<String, String>();        for (int i = 0; i < headers.length; i++) {            result.put(headers[i].getName(), headers[i].getValue());        }        return result;    }}

0 0
原创粉丝点击