Volley源码学习(二):网络请求处理,HurlStack类,BasicNetwork类,ByteArrayPool,PoolingByteArrayOutputStream

一.源码解析

volley用于处理网络请求的HurlStack类和BasicNetwork类,继承HttpStack接口

1.接口HttpStack,定义了方法HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders),处理网络请求,获得HttpResponse。

2.类HurlStack:使用httpconnection处理网络请求

主要方法:
方法:performRequest(Request<?> request, Map<String, String> additionalHeaders)
逻辑流程:获得url,new map添加request里的headers和additionalHeaders→有mUrlRewriter就重写url→获得connection = openConnection(parsedUrl, request);→遍历map,connection.addRequestProperty,为connection添加 headers.→获得responseCode并new responseStatus→response = new BasicHttpResponse(responseStatus);→ response.setEntity,设置entity→遍历,将connection的headers添加到response里,最后返回。
方法:setConnectionParametersForRequest(HttpURLConnection connection,Request<?> request)
根据request,为connection设置method,post,get,delete,put等
  public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        String url = request.getUrl();
        HashMap<String, String> map = new HashMap<String, String>();
        map.putAll(request.getHeaders());
        map.putAll(additionalHeaders);
        if (mUrlRewriter != null) {
            String rewritten = mUrlRewriter.rewriteUrl(url);
            if (rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
            }
            url = rewritten;
        }
        URL parsedUrl = new URL(url);
        HttpURLConnection connection = openConnection(parsedUrl, request);
        for (String headerName : map.keySet()) {
            connection.addRequestProperty(headerName, map.get(headerName));
        }
        setConnectionParametersForRequest(connection, request);
        // Initialize HttpResponse with data from the HttpURLConnection.
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        int responseCode = connection.getResponseCode();
        if (responseCode == -1) {
            // -1 is returned by getResponseCode() if the response code could not be retrieved.
            // Signal to the caller that something was wrong with the connection.
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                connection.getResponseCode(), connection.getResponseMessage());
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        response.setEntity(entityFromConnection(connection));
        for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
            if (header.getKey() != null) {
                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                response.addHeader(h);
            }
        }
        return response;
    }

3.类BaseNetwork

主要方法
方法:addCacheHeaders(Map<String, String> headers, Cache.Entry entry),如果存在Cache.Entry,headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
方法:NetworkResponse performRequest(Request<?> request):包装HurlStack类的方法,增加一些其他操作。
调用addCacheHeaders方法,为request增加CacheHeaders→调用hurlStack的performRequest方法获得httpResponse→获得statusLine,获得statusCode
→如果StatusCode==304,则直接返回NetworkResponse,将NetWorkResponse的notModified设为true→对于204等没有content的状态码,再确认一次,将
httpResponse的entity转换到responseContents里→状态码为200-299时,返回NetworkResponse,但notModified为false.→不是时,抛出IOException
→在catch里根据responseContent是否为null,进行对应处理,抛出异常。
方法:entityToBytes(HttpEntity entity),将entity转换为byte[],利用到PoolingByteArrayOutputStream类,ByteArrayPool类,之前ByteArrayPool类是一个持有
不同长度的byte[]的pool,可以提供大于目标size的byte[],防止不同size的byte[]重复创建,提供性能。PoolingByteArrayOutputStream则是利用ByteArrayPool
提供的byte[]的输出流。
 public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();
        while (true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map<String, String> responseHeaders = new HashMap<String, String>();
            try {
                // Gather headers.
                Map<String, String> headers = new HashMap<String, String>();
                addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();

                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                // Handle cache validation.
                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.
                if (httpResponse.getEntity() != null) {
                  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();
                }
                return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
            } catch (SocketTimeoutException e) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException e) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException e) {
                throw new RuntimeException("Bad URL " + request.getUrl(), e);
            } catch (IOException e) {
                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);
                }
            }
        }
    }

3.类NetworkResponse

NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,boolean notModified)构造方法就可以看出用途
包装后,如果server返回304,notModified就是true说明在指定时间未修改,直接从本地cache获取。

4.类ByteArrayPool,提供不同size的byte[],提高性能

getBuf(int len),trim(),returnBuf(byte[] buf)3个主要方法。
public class ByteArrayPool 
mBuffersByLastUse = new LinkedList<byte[]>(); //用于将最近使用的byte[]添加到末尾,删除byte[]时,删除头部的,即删除最久不用的
private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);    //按大小顺序排列的list<pre name="code" class="html">public synchronized void returnBuf(byte[] buf) {   //将buf添加到pool里
        if (buf == null || buf.length > mSizeLimit) {
            return;
        }
        mBuffersByLastUse.add(buf);      //添加到末尾,表明最近使用的
        int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);      //使用二分法将buf插入到mBufferBysize里
        if (pos < 0) {
            pos = -pos - 1;
        }
        mBuffersBySize.add(pos, buf);
        mCurrentSize += buf.length;
        trim();          //添加后,确认是否超出limitSize,超出就删除旧的byte[]
    }<pre name="code" class="html">    private synchronized void trim() {
        while (mCurrentSize > mSizeLimit) {
            byte[] buf = mBuffersByLastUse.remove(0); //找到eldest的byte[]
            mBuffersBySize.remove(buf); //删除
            mCurrentSize -= buf.length;
        }
    }
 
   
    public synchronized byte[] getBuf(int len) {              //根据len获得大于该len的byte[]
        for (int i = 0; i < mBuffersBySize.size(); i++) {
            byte[] buf = mBuffersBySize.get(i);
            if (buf.length >= len) {
                mCurrentSize -= buf.length;
                mBuffersBySize.remove(i);                //移除buf
                mBuffersByLastUse.remove(buf);
                return buf;
            }
        }
        return new byte[len];
    }
 
   
 
   
 
   

5.类PoolingByteArrayOutputStream,使用ByteArrayPool的ByteArrayOutputStream,提供性能

   private void expand(int i) {    //扩展读取时用的buf
        /* Can the buffer handle @i more bytes, if not expand it */
        if (count + i <= buf.length) {
            return;
        }
        byte[] newbuf = mPool.getBuf((count + i) * 2);     //从mPool里获得byte[],size至少是原来的2倍
        System.arraycopy(buf, 0, newbuf, 0, count);
        mPool.returnBuf(buf);                         //将不用的buf return到pool里保存
        buf = newbuf;      //buf指向newbuf
    }</span><pre name="code" class="html">    public synchronized void write(byte[] buffer, int offset, int len) {  
        expand(len);         //写时调用expand方法,检查是否需要扩展,
        super.write(buffer, offset, len);
    }
    @Override
    public void close() throws IOException { //关闭,或回收时都将buf 还回pool
        mPool.returnBuf(buf);
        buf = null;
        super.close();
    }
    @Override
    public void finalize() {
        mPool.returnBuf(buf);
    }


 
    






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值