volley源码解析

一,先简单说下几个步骤:

(1)初始化请求队列,调用Volly.newRequestQueue()获取一个默认的RequestQueue。

(2)创建并开启4条网络调度器,缓存调度器。

(3)CacheDispatcher的run方法会从缓存队列中死循环取数据,如果没有缓存就将请求放到网络请求队列。

(3)NetworkDispatcher调度器从RequestQueue死循环取出request,传给NetWork的performRequest方法。

(4)最终会执行HttpStack.performRequest方法,通过HttpURLConnection进行网络请求。

二,具体分析

(1)先看Volley类的newRequestQueue方法,请求都是加到请求队列中执行的。

(1.1)public static RequestQueue newRequestQueue(Context context) {
           return newRequestQueue(context, null);//一般传的HttpStack 都是null
       }//真正的网络请求是由HttpStack定义的,这是一个接口,唯一的方法就是执行网络请求获取响应。
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);//定义缓存路径保存需要缓存的请求成功后的返回数据
    //......配置userAgent,是请求代理的标识,用于AndroidHttpClient的创建
    if (stack == null) {//以下两个实现类对应不同的网络请求的底层实现
        if (Build.VERSION.SDK_INT >= 9) {//判断api版本
            stack = new HurlStack();//基于HttpURLConnection,和HttpClientStack一样是HttpStack的实现类,
        } else {
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));//基于HttpClient
        }
    }
    Network network = new BasicNetwork(stack);//网络接口的基本实现,处理网络请求或失败重试,详见(3.2)
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);//调用了下面的构造方法
    queue.start();
    return queue;
}//(1.2)
(2)再看RequestQueue类的构造方法和start方法,可以看到在构造方法中,第一,开了4个默认线程池,即网络调度器;第二,创建并启动一个CacheDispatcher。
public RequestQueue(Cache cache, Network network) {
    this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);//默认为4,用于决定开启多少条网络调度。他又调用另一个构造方法
}//(2.1)
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
    this(cache, network, threadPoolSize,//ExecutorDelivery类是Volley框架中的结果分发类
            new ExecutorDelivery(new Handler(Looper.getMainLooper())));//传入Handler是为了能够让需要的方法跑在主线程
}//(2.2)
public RequestQueue(Cache cache, Network network, int threadPoolSize,
        ResponseDelivery delivery) {
    mCache = cache;//缓存处理类的实例
    mNetwork = network;//网络处理类的实例
    mDispatchers = new NetworkDispatcher[threadPoolSize];//网络调度器的实例
    mDelivery = delivery;//结果分发类的实例
}//(2.3)
到这儿终于创建好RequestQueue了,紧接着是start,开启1条缓存调度和4条网络调度。
public void start() {
    stop();  // 终止正在运行的线程,缓存调度mCacheDispatcher.quit(),网络调度mDispatchers循环quit(),暂停线程
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    mCacheDispatcher.start();//开启缓存调度
    for (int i = 0; i < mDispatchers.length; i++) {//开启网络调度,一般4条
        NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                mCache, mDelivery);
        mDispatchers[i] = networkDispatcher;
        networkDispatcher.start();
    }
}(2.4)

(3)网络调度类NetworkDispatcher,这个类继承Thread类,本身是一个线程,只有一个构造方法,重写了run方法。

NetworkDispatcher只负责调度并不负责具体的网络请求,它相当于一个中转站,只是将request从RequestQueue手中取来,然后原封不动的交给mNetwork

public NetworkDispatcher(BlockingQueue<Request<?>> queue,Network network, Cache cache, ResponseDelivery delivery) {
    mQueue = queue;//优先级队列
    mNetwork = network;//网络处理器
    mCache = cache;//缓存处理器
    mDelivery = delivery;//结果分发类
}(3.1)

在请求队列start()的时候,就创建并开启了4条网络线程调度,所以看下NetworkDispatcher的run方法:

@Override
public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//设置最高线程优先级
    while (true) {//while死循环,不断的试图从mQueue队列中取出request
        long startTimeMs = SystemClock.elapsedRealtime();
        Request<?> request;
        try {
            request = mQueue.take();
        } catch (InterruptedException e) {
            if (mQuit) {//interrupt()会尝试中断本线程,我们可能会被打断,因为这是该放弃的时候了
                return;
            }
            continue;
        }

        try {
            request.addMarker("network-queue-take");// 调试标记:以成功取出队列中的request
            if (request.isCanceled()) {//如果请求被取消,则不再继续请求
                request.finish("network-discard-cancelled");
                continue;
            }
            addTrafficStatsTag(request);// 流量统计标记,如果api大于14,配合DDMS工具统计流量使用情况
            // 开始真正的网络请求,从这儿看出NetworkDispatcher为什么是网络调度线程,因为它只负责将request传给mNetwork网络                                               
               处理类,本身并不执行网络请求,这个方法返回的是NetworkResponse(一个实体类,封装返回数据,封装的参数分别是int状态码,byta[]返回数据,Map<String,String>响应头,boolean无修改标记)
            NetworkResponse networkResponse = mNetwork.performRequest(request);
            request.addMarker("network-http-complete");//调试标记:网络请求完成(因线程异步,该标记只做调试之用)
            // 如果服务器返回无修改,并requset以完成分发,说明进行了重复的请求,移除该request
            if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                request.finish("not-modified");
                continue;
            }
            // 交由Request进行解析Response
            //parseNetworkResponse是Request抽象类的一个抽象方法,实现方法由Request的子类去实现
            Response<?> response = request.parseNetworkResponse(networkResponse);
            request.addMarker("network-parse-complete");// 调试标记:网络请求解析完成
            // 如果需要缓存,将返回的数据加入到缓存处理类中
            if (request.shouldCache() && response.cacheEntry != null) {
                mCache.put(request.getCacheKey(), response.cacheEntry);
                request.addMarker("network-cache-written");
            }
            // 最后由结果分发类调用postResponse发起回调
            request.markDelivered();
            mDelivery.postResponse(request, response);
        } catch (VolleyError volleyError) {
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            parseAndDeliverNetworkError(request, volleyError); //此方法通过request.parseNetworkError(volleyError)解析这个错误,然后发起错误回调,值得一提的是parseNetworkError在request中是一个没有意义的方法,传进去的VolleyError会被原封不动的返回,但子类可以复写该方法,完成自己的错误解析。
        } catch (Exception e) {
            VolleyLog.e(e, "Unhandled exception %s", e.toString());
            VolleyError volleyError = new VolleyError(e);
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            mDelivery.postError(request, volleyError);
        }
    }
}(3.2)
public void quit() {//在RequestQueue调用stop时被调用了
    mQuit = true;//标记取消网络请求,并中断该线程,mQuit 为true,则该线程跳出while循环
    interrupt();
}(3.3)

(4)NetworkDispatcher只负责中转,从RequestQueue取出request交给接口NetWork,BasicNetwork是接口的实现类:

public interface Network {//里面只有一个方法,用于执行请求
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}(4.1)
在newRequestQueue时,实现了网络接口,Network network = new BasicNetwork(stack);,随后这个network便传给了请求队列,然后又传给网络调度器,最后调用mNetwork.performRequest(request)执行网络请求。
public BasicNetwork(HttpStack httpStack) {//在newRequestQueue时新建的构造方法
    this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));//创建了缓存池,大小4096,即4KB
}(4.2)
public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
    mHttpStack = httpStack;
    mPool = pool;
}(4.3)
(4.4)performRequest返回的是一个封装返回数据的实体类对象。这个方法只是对网络请求返回数据的封装处理
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();//得到开机时间的毫秒值
    while (true) {//while死循环
        HttpResponse httpResponse = null;
        byte[] responseContents = null;
        Map<String, String> responseHeaders = Collections.emptyMap();
        try {
            Map<String, String> headers = new HashMap<String, String>();
            addCacheHeaders(headers, request.getCacheEntry());//添加缓存请求头
            httpResponse = mHttpStack.performRequest(request, headers);//看出真正执行网络请求的是mHttpStack
            StatusLine statusLine = httpResponse.getStatusLine();//得到状态行
            int statusCode = statusLine.getStatusCode();//得到状态码
            responseHeaders = convertHeaders(httpResponse.getAllHeaders());//得到响应头
            if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回304无修改,则返回
                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, statusLine.getReasonPhrase(), entry.data,
                        entry.responseHeaders, true,
                        SystemClock.elapsedRealtime() - requestStart);               
            }        
            if (httpResponse.getEntity() != null) {//返回204无修改,没有读出内容就给一个0长度字节的数组
              responseContents = entityToBytes(httpResponse.getEntity());
            } else {
              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();//状态码不正确抛出异常
            }//经过以上种种判断,封装成NetWorkResponse给予返回
            return new NetworkResponse(statusCode, statusLine.getReasonPhrase(), responseContents, responseHeaders, false,SystemClock.elapsedRealtime() - requestStart);//返回封装的数据,状态码,返回数据,响应头,无修改标记
        } catch (SocketTimeoutException e) {//尝试重新请求,重试策略类RetryPolicy,在Request的构造方法中创建,先获取对象
            attemptRetryOnException("socket", request, new TimeoutError());//retryPolicy= request.getRetryPolicy();
        } catch (ConnectTimeoutException e) {//然后调用retryPolicy.retry(exception);
            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, httpResponse.getStatusLine().getReasonPhrase(), responseContents,
                        responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                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);
            }
        }
    }
}

(5)HttpStack的源码

//Request封装了超时时间,请求方式、参数、url等网络请求所必须的参数,通过变换不同的属性参数(最基本的如请求方式GET和Post),可以获取不同的网络请求。而真正的网络请求是HttpStack

public interface HttpStack {Volley中真正去执行联网的类,返回的信息封装成HttpResponse
  public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)throws IOException, AuthFailureError;//真正去执行联网的方法,与NetWork接口的一个方法同名
}

对于HttpClientStack和HurlStack,二者的工作思路是:

首先从volley的request内获取各个属性,如超时间、请求方式、url、参数;

然后创建网络请求,HttpClientStack创建HttpClient,HurlStack创建HttpURLConnection;

对网络请求设置各个属性参数。

最后定义执行网络请求的方法,并获取响应,将响应返回去。

以上思路在源码细节中是从HurlStack的performRequest开始

public HurlStack() {this(null);}
public HurlStack(UrlRewriter urlRewriter) {this(urlRewriter, null);}
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
    mUrlRewriter = urlRewriter;//是HurlStack的一个内部接口,用于URL的重置,一般给null
    mSslSocketFactory = sslSocketFactory;//https协议用到的类,一般也是null
}

其中传入的参数request,里面设置了很多http的属性,如超时,是否缓存,还有一个参数设置头信息

再看看其中几个重要方法:openConnection,setConnectionParametersForRequest ,entityFromConnection

 

private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
    HttpURLConnection connection = createConnection(url);//很简单,只是创建了HttpURLConnection,
                                                           通过 url.openConnection()
    int timeoutMs = request.getTimeoutMs();
    connection.setConnectTimeout(timeoutMs);//设置HttpURLConnection的一些参数,连接超时
    connection.setReadTimeout(timeoutMs);//读超时
    connection.setUseCaches(false);//关闭缓存
    connection.setDoInput(true);//开启输入
    if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {//支持https
        ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
    }
    return connection;//返回HttpURLConnection对象
}

setConnectionParametersForRequest :设置请求方式,包含get,delete,post,put等

private static HttpEntity entityFromConnection(HttpURLConnection connection) {
    BasicHttpEntity entity = new BasicHttpEntity();//设置实体
    InputStream inputStream;
    try {
        inputStream = connection.getInputStream();
    } catch (IOException ioe) {
        inputStream = connection.getErrorStream();
    }
    entity.setContent(inputStream);
    entity.setContentLength(connection.getContentLength());
    entity.setContentEncoding(connection.getContentEncoding());
    entity.setContentType(connection.getContentType());
    return entity;//将connection得到的信息封装成实体(BasicHttpEntity)返回
}

到这儿volley网络请求这一条线已经全部完成。

(6)接下来看缓存调度器CacheDispatcher,也是一个线程,继承Thread,也是在请求队列的start方法中调用的start方法

public CacheDispatcher(
        BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
        Cache cache, ResponseDelivery delivery) {
    mCacheQueue = cacheQueue;//缓存队列
    mNetworkQueue = networkQueue;//网络队列
    mCache = cache;//缓存处理类
    mDelivery = delivery;//结果分发类
}
@Override
public void run() {
    if (DEBUG) VolleyLog.v("start new dispatcher");
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    mCache.initialize();//将缓存数据读入内存,初始化了缓存数据
    while (true) {
        try {
            final Request<?> request = mCacheQueue.take();//从缓存队列中取出request
            request.addMarker("cache-queue-take");//调试信息
            if (request.isCanceled()) {//如果请求已取消,则中断任务
                request.finish("cache-discard-canceled");
                continue;
            }
            Cache.Entry entry = mCache.get(request.getCacheKey());//试图从缓存中取得该项目
            if (entry == null) {//是空的就加入网络队列
                request.addMarker("cache-miss");
                mNetworkQueue.put(request);
                continue;
            }
            if (entry.isExpired()) {//如果缓存过期,加入网络队列
                request.addMarker("cache-hit-expired");
                request.setCacheEntry(entry);
                mNetworkQueue.put(request);
                continue;
            }
            request.addMarker("cache-hit");//命中缓存,交给request解析
            Response<?> response = request.parseNetworkResponse(
                    new NetworkResponse(entry.data, entry.responseHeaders));
            request.addMarker("cache-hit-parsed");

            if (!entry.refreshNeeded()) {//再次判断缓存过期,应该是因为异步处理,可能导致过程中缓存过期
                mDelivery.postResponse(request, response);//命中缓存,分发事件
            } else {
                request.addMarker("cache-hit-refresh-needed");//命中缓存过期
                request.setCacheEntry(entry);//分发结果,并向网络请求一次
                response.intermediate = true;
                mDelivery.postResponse(request, response, new Runnable() {
                    @Override
                    public void run() {
                        try {
                            mNetworkQueue.put(request);
                        } catch (InterruptedException e) {
                            // Not much we can do about this.
                        }
                    }
                });
            }

        } catch (InterruptedException e) {         
            if (mQuit) {//程序中断,退出循环
                return;
            }
            continue;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值