Volley源码分析

Volley源码分析

流程图

流程图有错,网络请求线程应该默认为四个
注:流程图有错,网络请求线程应该默认为四个

请求初始化

我们使用volley框架,一般会先创建请求队列 mRequestQueue = Volley.newRequestQueue(context);
会走这个构造:

    /**
         * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
         *
         * @param context A {@link Context} to use for creating the cache dir.
         * @return A started {@link RequestQueue} instance.
         */
        public static RequestQueue newRequestQueue(Context context) {
            return newRequestQueue(context, null);
        }

这个一个参数的构造最终会走public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)这个构造,stack值为null,maxDiskCacheBytes值为-1,代表使用默认的HttpStack和默认磁盘缓存大小,该构造代码如下:

    //磁盘缓存目录,在data/data/包名/cache/volley目录
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

    String userAgent = "volley/0";
    try {
        String packageName = context.getPackageName();
        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
        userAgent = packageName + "/" + info.versionCode;
    } catch (NameNotFoundException e) {
    }

    //因为默认stack为null,所以会根据sdk版本创建不同的HttpStack,其中HurlStack是用HttpURLConnection进行网络请求的
    if (stack == null) {
        if (Build.VERSION.SDK_INT >= 9) {
            stack = new HurlStack();
        } else {
            // Prior to Gingerbread, HttpUrlConnection was unreliable.
            // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
        }
    }

    //创建一个BasicNetwork对象,Network是一个接口,有一个方法public NetworkResponse performRequest(Request<?> request);

    Network network = new BasicNetwork(stack);

    RequestQueue queue;
    if (maxDiskCacheBytes <= -1)
    {
        // No maximum size specified
        //创建请求队列
        queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    }
    else
    {
        // Disk cache size specified
        queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
    }

    queue.start();

    return queue;

其中queue = new RequestQueue(new DiskBasedCache(cacheDir), network)创建请求队列中new DiskBasedCache(cacheDir)会走如下构造,创建默认大小为5MB的磁盘缓存

    public DiskBasedCache(File rootDirectory) {
    this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
    }

而new RequestQueue(new DiskBasedCache(cacheDir), network)构造最终会走这个构造:

    public RequestQueue(Cache cache, Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

由以上代码可以看出,系统会创建一个网络分发线程数组mDispatchers,线程数默认为4,并创建一个响应分发器mDelivery

    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
    private final ResponseDelivery mDelivery;
    private NetworkDispatcher[] mDispatchers;

至此,请求队列初始化完毕

请求队列启动

请求队列启动是调用queue.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();
    }
}

由上可以看出,会创建一个缓存器CacheDispatcher,其实它也是个线程,并其启动它;然后遍历网络分发线程数组mDispatchers,创建网络请求线程,赋值并启动网络分发线程数组,其长度为4,也就是有4个网络请求线程,创建缓存线程和网络请求线程构造都有四个参数,mCacheQueue, mNetworkQueue, mCache, mDelivery;其中 mCache, mDelivery前面讲过一个是缓存对象,一个是响应分发器,其余两个是缓存请求队列和网络请求队列,之后我们创建的网络请求就会按情况添加到队列中.

线程启动会走run()方法,我们先看缓存线程run方法

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

    Request<?> request;
    while (true) {
        // release previous request object to avoid leaking request object when mQueue is drained.
        request = null;
        try {
            // Take a request from the queue.
            request = mCacheQueue.take();
        } catch (InterruptedException e) {
            // We may have been interrupted because it was time to quit.
            if (mQuit) {
                return;
            }
            continue;
        }
        ...
}

从这里可以看出mCacheQueue.take(),缓存队列会监视队列中的请求,如果有就会取出,然后处理,网络请求队列也是如此,在这之前我们先看这个mCache.initialize(),缓存的初始化:

    public synchronized void initialize() {
    if (!mRootDirectory.exists()) {
        if (!mRootDirectory.mkdirs()) {
            VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
        }
        return;
    }

    File[] files = mRootDirectory.listFiles();
    if (files == null) {
        return;
    }
    for (File file : files) {
        BufferedInputStream fis = null;
        try {
            fis = new BufferedInputStream(new FileInputStream(file));
            CacheHeader entry = CacheHeader.readHeader(fis);
            entry.size = file.length();
            //将缓存的头信息存入集合中
            putEntry(entry.key, entry);
        } catch (IOException e) {
            if (file != null) {
               file.delete();
            }
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException ignored) { }
        }
    }
}

其中putEntry(entry.key, entry)会先把缓存的头信息取出来存入Map<> mEntries中,而不会读取缓存,到请求发生时才会读取缓存,这样既节约了时间,又避免内存溢出.

网络请求处理
  • 缓存线程的请求处理

    我们会调用RequestQueue的add(Request request)方法将请求添加进队列,由于缓存线程已启动,就会取出这个请求,进行处理:

        try {
                request.addMarker("cache-queue-take");
    
                // If the request has been canceled, don't bother dispatching it.
                //请求取消
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }
    
                // Attempt to retrieve this item from cache.
                //没有缓存,将请求添加进网络请求队列
                Cache.Entry entry = mCache.get(request.getCacheKey());
                if (entry == null) {
                    request.addMarker("cache-miss");
                    // Cache miss; send off to the network dispatcher.
                    mNetworkQueue.put(request);
                    continue;
                }
    
                // If it is completely expired, just send it to the network.
                //缓存过期,将请求添加进网络请求队列
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }
    
                // We have a cache hit; parse its data for delivery back to the request.
                request.addMarker("cache-hit");
                Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");
    
                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    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;
    
                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    final Request<?> finalRequest = request;
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(finalRequest);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
            }
    

    由上面可以看出,当缓存找到了并且不过期,就会从缓存中读取数据,通过Response<> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));将我们实现的parseNetworkResponse方法调用并返回Response对象

    最后调用mDelivery.postResponse(request, response),其中mDelivery就是我们初始化请求队列时创建的响应分发器

        public RequestQueue(Cache cache, Network network, int threadPoolSize) {
        this(cache, network, threadPoolSize,
                new ExecutorDelivery(new Handler(Looper.getMainLooper())));
        }
    

    该分发器绑定一个主线程的handler,会在将响应post到主线程进行,通过

    @Override
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
        request.markDelivered();
        request.addMarker("post-response");
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }
    

    执行ResponseDeliveryRunnable的run()方法,

            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }
    

    从这里可以看到,mRequest会调用deliverResponse和deliverError方法最终会回调我们实现的onResponse(response)和onErrorResponse(error)方法.

         @Override
    protected void deliverResponse(T response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }
    public void deliverError(VolleyError error) {
        if (mErrorListener != null) {
            mErrorListener.onErrorResponse(error);
        }
    }
    
  • 网络线程的请求处理

    网络线程的请求处理跟缓存线程的请求处理大致相同,只不过要从网络获取数据,再缓存到本地磁盘,然后再由响应分发器分发到主线程

    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");
                continue;
            }
    
            addTrafficStatsTag(request);
    
            // Perform the network request.
            //请求网络数据
            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.
            if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                request.finish("not-modified");
                continue;
            }
    
            // Parse the response here on the worker thread.
            //解析数据
            Response<?> response = request.parseNetworkResponse(networkResponse);
            request.addMarker("network-parse-complete");
    
            // Write to cache if applicable.
            // TODO: Only update cache metadata instead of entire record for 304s.
            //缓存到本地磁盘
            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);
        } catch (VolleyError volleyError) {
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            parseAndDeliverNetworkError(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);
        }
    

    其中请求网络数据通过NetworkResponse networkResponse = mNetwork.performRequest(request)实现,mNetwork就是初始化时的Network network = new BasicNetwork(stack),sdk版本9以上是使用

    BasicNetwork类
     public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        ...
        httpResponse = mHttpStack.performRequest(request, headers);
    }
    
    HttpStack类
     public NetworkResponse performRequest(Request<?> request) throws throws IOException, AuthFailureError {
        ...
        HttpURLConnection connection = openConnection(parsedUrl, request);
    }
    

    以上就是volley源码的全部解析.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值