Volley源码解析

现在这个框架已经被用得很少了,但是目前我们项目中还有用到,那就尝试分析源码吧。
源码地址:https://github.com/google/volley

一.源码解析步骤:

1. volley类:
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
        BasicNetwork network;
        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                /***
                * 在9及以上版本,采用HurlStack ,这个类中封装了用HttpURLConnection 处理网络请求返回HttpResponse 
                *
                ***/
                network = new BasicNetwork(new HurlStack());
            } else {

                String userAgent = "volley/0";
                try {
                    String packageName = context.getPackageName();
                    PackageInfo info =
                            context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
                    userAgent = packageName + "/" + info.versionCode;
                } catch (NameNotFoundException e) {
                }
                //在9以下的版本,采用HttpClientStack,里面封装了HttpClient处理网络请求返回HttpResponse 
                network =
                        new BasicNetwork(
                                new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
            }
        } else { //这里使用户自定义业务处理网络请求返回HttpResponse 
            network = new BasicNetwork(stack);
        }
            //创建好缓存目录,将上述处理HttpResponse 的network封装到RequestQueue中,调用queue中的start方法,开始分发这个任务
        return newRequestQueue(context, network);
    }
2. RequestQueue类:

这个类中封装了一个线程池来调度和派发网络请求任务,默认线程的数量是4。主要是看里面的start方法。

 /** Starts the dispatchers in this queue. */
    public void start() {
        stop(); // Make sure any currently running dispatchers are stopped.这里是在请求开始的时候,将当前正在运行的线程中断
        // Create the cache dispatcher and start it.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();//开启缓存请求线程任务

        // Create network dispatchers (and corresponding threads) up to the pool size.
        for (int i = 0; i < mDispatchers.length; i++) {//根据线程池中线程的数量,创建网络请求线程任务
            NetworkDispatcher networkDispatcher =
                    new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }
3. NetworkDispatcher类

这个类继承Thread , 所以主要就是看run方法,看看如何处理任务的。

@Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//设置线程的级别
        while (true) {//开启死循环
            try {
                processRequest();//处理网络请求
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {//如果线程已经被中断了,捕获中断异常,返回。
                    Thread.currentThread().interrupt();
                    return;
                }
                VolleyLog.e(
                        "Ignoring spurious interrupt of NetworkDispatcher thread; "
                                + "use quit() to terminate it");
            }
        }
    }

// 处理网络请求的逻辑
 @VisibleForTesting
    void processRequest(Request<?> request) {
        long startTimeMs = SystemClock.elapsedRealtime();
        try {
            request.addMarker("network-queue-take");//给当前线程加上标记,主要是为了调试用的

            // If the request was cancelled already, do not perform the
            // network request.
            if (request.isCanceled()) {
                request.finish("network-discard-cancelled");//从请求队列中去掉此次请求标记
                request.notifyListenerResponseNotUsable();
                return;
            }

            addTrafficStatsTag(request);

            // Perform the network request.处理网络请求,返回NetworkResponse 
            NetworkResponse networkResponse = mNetwork.performRequest(request);
            request.addMarker("network-http-complete");//当前请求线程加上标记

            // If the server returned 304 AND we delivered a response already,
            // we're done -- don't deliver a second identical response.
            //如果服务端返回304并且已经将结果返回分发出去了,就标记此次请求已经完成
            if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                request.finish("not-modified");
                request.notifyListenerResponseNotUsable();
                return;
            }

            // Parse the response here on the worker thread.
            //抽象方法,将请求返回封装成泛型response,由调用者自己实现
            Response<?> response = request.parseNetworkResponse(networkResponse);
            request.addMarker("network-parse-complete");//线程标记

            //如果请求头需要缓存的话,需要将key和entry保存在缓存中
            if (request.shouldCache() && response.cacheEntry != null) {
                mCache.put(request.getCacheKey(), response.cacheEntry);
                request.addMarker("network-cache-written");//线程标记
            }

            // Post the response back.
            request.markDelivered();//线程标记
            mDelivery.postResponse(request, response);//将请求和响应分发出去,包括正确的和错误的响应结果
            request.notifyListenerResponseReceived(response);//用listener回调请求结果
        } catch (VolleyError volleyError) {
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            parseAndDeliverNetworkError(request, volleyError);
            request.notifyListenerResponseNotUsable();
        } 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);
            request.notifyListenerResponseNotUsable();
        }
    }

4.CacheDispatcher类:

这也是继承Thread ,查看其run方法:

 @Override
    public void run() {
        if (DEBUG) VolleyLog.v("start new dispatcher");
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // Make a blocking call to initialize the cache.
        mCache.initialize();//缓存初始化

        while (true) {//死循环处理缓存请求
            try {
                processRequest();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {//捕捉线程中断异常,并中断这次任务
                    Thread.currentThread().interrupt();
                    return;
                }
                VolleyLog.e(
                        "Ignoring spurious interrupt of CacheDispatcher thread; "
                                + "use quit() to terminate it");
            }
        }
    }


//从缓存队列中取出一个请求开始处理
 @VisibleForTesting
    void processRequest(final Request<?> request) throws InterruptedException {
        request.addMarker("cache-queue-take");//线程标记,调试用途

        // If the request has been canceled, don't bother dispatching it.
        if (request.isCanceled()) {
            request.finish("cache-discard-canceled");
            return;
        }

        // 根据key值获取存储的entry
        Cache.Entry entry = mCache.get(request.getCacheKey());
        if (entry == null) {//如果为空,说明缓存内容已经丢失了
            request.addMarker("cache-miss");
            // Cache miss; send off to the network dispatcher.
            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {//去除重复请求
                mNetworkQueue.put(request);//添加到网络请求队列中
            }
            return;
        }

        // If it is completely expired, just send it to the network.
        if (entry.isExpired()) {//如果有缓存,但是已经过期了
            request.addMarker("cache-hit-expired");//线程标记
            request.setCacheEntry(entry);
            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {//去除重复请求
                mNetworkQueue.put(request);//添加到网络请求队列中
            }
            return;
        }

        // We have a cache hit; parse its data for delivery back to the request.
        request.addMarker("cache-hit");//缓存有效
        //抽象方法,将相应的信息封装成泛型response
        Response<?> response =
                request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
        request.addMarker("cache-hit-parsed");

        if (!entry.refreshNeeded()) {
            // 没有完全过期的缓存,分发出去
            mDelivery.postResponse(request, response);
        } else {
            // Soft-expired cache hit. We can deliver the cached response,
            // but we need to also send the request to the network for
            // refreshing.
            request.addMarker("cache-hit-refresh-needed");
            request.setCacheEntry(entry);
            // Mark the response as intermediate.
            response.intermediate = true;

            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                // Post the intermediate response back to the user and have
                // the delivery then forward the request along to the network.
                mDelivery.postResponse(
                        request,
                        response,
                        new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    mNetworkQueue.put(request);//添加到网络请求队列
                                } catch (InterruptedException e) {
                                    // Restore the interrupted status
                                    Thread.currentThread().interrupt();
                                }
                            }
                        });
            } else {
                // request has been added to list of waiting requests
                // to receive the network response from the first request once it returns.
                mDelivery.postResponse(request, response);
            }
        }
    }
5.StringRequest类

从上面我们分析中可以看到一个抽象方法:

Response<?> response = request.parseNetworkResponse(networkResponse)

调用者可以采用StringRequest来解析Response

  @Override
    @SuppressWarnings("DefaultCharset")
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
           //根据responseData和响应头中的字符集,创建String类型
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            // Since minSdkVersion = 8, we can't call
            // new String(response.data, Charset.defaultCharset())
            // So suppress the warning instead.
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
6.Volley为什么不能处理大批量数据?

在AdaptedHttpStack 中,在处理返回HttpResponse的时候,有这样一行抛出异常:

@Override
    public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        org.apache.http.HttpResponse apacheResp;
        try {
            apacheResp = mHttpStack.performRequest(request, additionalHeaders);
        } catch (ConnectTimeoutException e) {
            // BasicNetwork won't know that this exception should be retried like a timeout, since
            // it's an Apache-specific error, so wrap it in a standard timeout exception.
            throw new SocketTimeoutException(e.getMessage());
        }

        int statusCode = apacheResp.getStatusLine().getStatusCode();

        org.apache.http.Header[] headers = apacheResp.getAllHeaders();
        List<Header> headerList = new ArrayList<>(headers.length);
        for (org.apache.http.Header header : headers) {
            headerList.add(new Header(header.getName(), header.getValue()));
        }

        if (apacheResp.getEntity() == null) {
            return new HttpResponse(statusCode, headerList);
        }

//服务端返回long类型的数据,将它强转为int类型的时候,如果数据量过大,int和long类型肯定不相等,这个时候就抛出异常,提示数据量太大了。
        long contentLength = apacheResp.getEntity().getContentLength();
        if ((int) contentLength != contentLength) {
            throw new IOException("Response too large: " + contentLength);
        }

        return new HttpResponse(
                statusCode,
                headerList,
                (int) apacheResp.getEntity().getContentLength(),
                apacheResp.getEntity().getContent());
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值