美文网首页
Android 浅析 Volley (二) 原理

Android 浅析 Volley (二) 原理

作者: CodePlayer_Jz | 来源:发表于2016-03-21 21:09 被阅读1240次

    Android 浅析 Volley (二) 原理


    前言

    Linus Benedict Torvalds : RTFSC – Read The Fucking Source Code

    概括

    本文通过对Volley源码进行分析来打通Volley的流程,并且知晓其原理,Volley的整体结构比较简单,但是细节有很多值得学习的地方。

    Volley 原理图

    Volley初始化

    RequestQueue mQueue = Volley.newRequestQueue(this);
    Volley的初始化就是简单的一行代码,但是里面做的事情比较复杂了。

    Volley

    这是Volley系统最主要的类之一,它用来初始化缓存目录和初始化下载响应队列。

    Volley.newRequestQueue(...)

    Creates a default instance of the worker pool and calls RequestQueue.start() on it.

    HttpStack stack = new HurlStack();
    Network network = new BasicNetwork(stack);
    
    File cacheDir = new File(...);
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    
    queue.start();
    

    这个函数不难,首先创建一个HttpStack对象和创建一个缓存文件,然后用创建的对象生成一个RequestQueue响应队列,最后调用RequestQueue.start()函数开始运行。

    那么我们开始深入去看下,首先看下RequestQueue。

    RequestQueue

    A request dispatch queue with a thread pool of dispatchers.
    Calling add(Request) will enqueue the given Request for dispatch, resolving from either cache or network on a worker thread, and then delivering a parsed response on the main thread.

    RequestQueue.RequestQueue(...)

    Creates the worker pool.
    初始化这里有几个关键的点:
    1、DEFAULT_NETWORK_THREAD_POOL_SIZE:访问网络的线程数,默认是4条线程。
    2、new ExecutorDelivery(new Handler(Looper.getMainLooper())):新建一个用来推出网络响应和错误的类。
    3、new NetworkDispatcher[threadPoolSize]:新建四条网络连接的线程。

    //@param cache A Cache to use for persisting responses to disk
    //@param network A Network interface for performing HTTP requests
    //@param threadPoolSize Number of network dispatcher threads to create
    //@param delivery A ResponseDelivery interface for posting responses and errors
    RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery)
    

    RequestQueue.Start()

    Starts the dispatchers in this queue.

    首先是创建一个CacheDispatcher缓存发送者,它是一个缓存发送的线程,然后调用CacheDispatcherstart()函数。
    然后循环创建NetworkDispatcher对象,因为默认的线程数是4,所以会循环4次创建网络调度(和相应的线程)到池大小,接着再调用start()函数。
    简单来说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。

    RequestQueue.Stop()

    Stops the cache and network dispatchers.

    将所有缓存和网络发送者停止。

    总结

    通过这几行简单的函数就创建了Volley的缓存和网络发送者队列,为以后的请求建立了机制。

    Volley添加请求

    Volley的添加请求也很简单。

    StringRequest stringRequest = new StringRequest(...);
    
    mQueue.add(stringRequest);
    

    创建一个Request对象并且添加进Queue队列就行了。看起来简单,实际,好吧,很复杂。

    RequestQueue

    RequestQueue.add()

    这里函数本身比较简单易懂,首先将Request标识为当前队列,然后添加到mCurrentRequests当前请求队列里。接着判断是否可以缓存,如果不行则直接调用网络队列进行请求。最后插入请求到现阶段,如果已经有一个缓存键的请求在进行。

    总结

    添加的操作是比较简单,但难的是里面的具体过程,缓存请求和网络请求都是独立线程,在添加到队列之后就会不断的去获取然后对网络或者缓存进行处理。

    Volley 类分析

    volley 类图

    工具类

    网络类

    HttpStack

    Performs an HTTP request with the given parameters.
    用于处理 Http 请求,返回请求结果的接口。

    HurlStack

    based on HttpURLConnection.
    实现 HttpStack 接口,基于HttpURLConnection进行各种请求方式的请求封装。

    BasicNetwork

    A network performing Volley requests over an HttpStack.
    一个基于HttpStack执行Volley请求的网络。

    调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
    主要实现了以下功能:
    1、利用 HttpStack 执行网络请求。
    2、如果 Request 中带有实体信息,如 Etag,Last-Modify 等,则进行缓存新鲜度的验证,并处理 304(Not Modify)响应。
    3、如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束。

    Network

    An interface for performing requests.
    接口类,作为网络请求的主要接口,传入需要访问的执行信息,并且返回一个NetworkResponse网络响应对象。

    缓存类

    Cache

    An interface for a cache keyed by a String with a byte array as data.
    接口,一个可以获取请求结果,存储请求结果的缓存。

    Entry get(String key)

    通过 key 获取请求的缓存实体

    void put(String key, Entry entry)

    存入一个请求的缓存实体

    void remove(String key)

    移除指定的缓存实体

    void clear()

    清空缓存

    Entry内部类

    byte[] data : 请求返回的数据(Body 实体)
    String etag Http : 响应首部中用于缓存新鲜度验证的 ETag
    long serverDate Http : 响应首部中的响应产生时间
    long ttl : 缓存的过期时间
    long softTtl : 缓存的新鲜时间
    Map<String, String> responseHeaders : 响应的 Headers
    boolean isExpired() : 判断缓存是否过期,过期缓存不能继续使用
    boolean refreshNeeded() : 判断缓存是否新鲜,不新鲜的缓存需要发到服务端做新鲜度的检测

    NoCache

    什么缓存都没有。不做任何操作的缓存实现类,可将它作为构建RequestQueue的参数以实现一个不带缓存的请求队列。

    DiskBasedCache

    Cache implementation that caches files directly onto the hard disk in the specified directory. The default disk usage size is 5MB, but is configurable.

    void initialize()

    Initializes the DiskBasedCache by scanning for all files currently in the specified root directory. Creates the root directory if necessary.
    初始化,扫描缓存目录得到所有缓存数据摘要信息放入内存。

    Entry get(String key)

    Returns the cache entry with the specified key if it exists, null otherwise.
    从缓存中得到数据。先从缓存头中得到头部信息,然后读取缓存数据文件得到内容。

    void put(String key, Entry entry)

    Puts the entry with the specified key into the cache.
    将数据文件内容保存到缓存。先检查缓存是否已满,已满则先删除缓存中部分数据,然后再新建缓存文件。

    void pruneIfNeeded(int neededSpace)

    Prunes the cache to fit the amount of bytes specified.
    检查是否能再分配 neededSpace 字节的空间,如果不能则删除缓存中部分数据。

    void clear()

    Clears the cache. Deletes all cached files from disk.
    清空缓存。

    void remove(String key)

    Removes the specified key from the cache if it exists.
    删除缓存中某个元素。

    CacheHeader

    Handles holding onto the cache headers for an entry.
    缓存文件头部信息在entry里。

    ByteArrayPool

    ByteArrayPool is a source and repository of byte[] objects.

    byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。 主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。

    PoolingByteArrayOutputStream

    A variation of java.io.ByteArrayOutputStream that uses a pool of byte[] buffers instead of always allocating them fresh, saving on heap churn.

    Authenticator

    身份认证接口,用于基本认证或者摘要认证。这个类是 Volley 用于和身份验证打通的接口,比如 OAuth,不过目前的使用不是特别广泛和 Volley 的内部结合也不是特别紧密。

    AndroidAuthenticator

    继承 Authenticator,基于 Android AccountManager 的认证交互实现类。

    基础类

    NetworkResponse

    Data and headers returned from performRequest(Request).
    作为Network接口返回的值,RequestparseNetworkResponse(…)参数,是 Volley 中用于内部 Response 转换的核心类。

    封装了网络请求响应的 StatusCode,Headers 和 Body 等。

    成员变量

    int statusCode Http 响应状态码
    byte[] data Body 数据
    Map<String, String> headers 响应 Headers
    boolean notModified 表示是否为 304 响应
    long networkTimeMs 请求耗时

    内部 Response 转换流程图
    volley response

    CacheDispatcher

    Provides a thread for performing cache triage on a queue of requests.

    CacheDispatcher类是一个线程类,里面有四个比较重要的变量:
    1、BlockingQueue<Request<?>> mCacheQueue来自缓存的队列。
    2、BlockingQueue<Request<?>> mNetworkQueue将会访问网络的队列。
    3、Cache mCache缓存的处理类。
    4、ResponseDelivery mDelivery回调响应的类。

    CacheDispatcher.run()

    在线程被创建后马上就被执行了。里面首先会对缓存路径进行初始化工作。接着就进入一个无限的循环等待里。

    首先会从缓存队列出取出请求,如果队列为空则会一直阻塞直到队列有数据,接着尝试从缓存当中取出响应结果,如何为空的话则把这条请求加入到网络请求队列中,如果不为空的话再判断该缓存是否已过期,如果已经过期了则同样把这条请求加入到网络请求队列中,否则就认为不需要重发网络请求,直接使用缓存中的数据即可。之后会调用Request的parseNetworkResponse()方法来对数据进行解析,最后就是将解析出来的数据进行回调了。

    CacheDispatcher 流程图
    NetworkDispatcher

    NetworkDispatcher

    Provides a thread for performing network dispatch from a queue of requests.

    NetworkDispatcher类是一个线程类,里面有四个比较重要的变量:
    1、BlockingQueue<Request<?>> mQueue响应来自服务的队列。
    2、Network mNetwork 网络进度请求。
    3、Cache mCache缓存的处理类。
    4、ResponseDelivery mDelivery回调响应的类。

    NetworkDispatcher.run()

    在线程被创建后马上就被执行了。首先进入一个无限的循环等待里。等待任务进来。

    在接受到请求后会直接访问网络发送请求,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。

    NetworkDispatcher 流程图
    NetworkDispatcher

    ResponseDelivery

    一个返回结果的分发接口。

    有三个分发接口:
    1、解析一个从网络或缓存的响应并分发。
    postResponse(Request<?> request, Response<?> response);
    2、解析一个从网络或缓存的响应并分发。提供的运行将会在分发后被执行。
    postResponse(Request<?> request, Response<?> response, Runnable runnable);
    3、推送一个收到的错误。
    postError(Request<?> request, VolleyError error);

    RetryPolicy

    Retry policy for a request.

    void retry(VolleyError error) throws VolleyError
    确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。

    DefaultRetryPolicy

    Default retry policy for requests.

    实现 RetryPolicy,Volley 默认的重试策略实现类。主要通过在 retry(…) 函数中判断重试次数是否达到上限确定是否继续重试。
    其中mCurrentRetryCount变量表示已经重试次数。
    mBackoffMultiplier表示每次重试之前的 timeout 该乘以的因子。
    mCurrentTimeoutMs变量表示当前重试的 timeout 时间,会以mBackoffMultiplier作为因子累计前几次重试的 timeout。

    相关文章

      网友评论

          本文标题:Android 浅析 Volley (二) 原理

          本文链接:https://www.haomeiwen.com/subject/vpgklttx.html