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

来源:互联网 发布:unity3d 离散事件仿真 编辑:程序博客网 时间:2024/06/16 15:52

一.源码解析

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









0 0
原创粉丝点击