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


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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值