Volley点滴

2017-03-05  本文已影响83人  LilacZiyun

编者按: 本博文主要记录我对Volley的理解以及从网上查阅的一些资料,主要用作一个学习笔记,若是有读者发现其中有理解错误之处,还望评论区帮忙指出,谢谢

Q & A:

  1. Q: Volley为什么在2.3以前使用HttpClientStack,而在2.3以后使用HurlStack?
    A: 一般来说,HttpURLConnection相对轻量级,也比较小,而Apache HTTP Client接口多,比较大,所以一般情况下HttpURLConnection是最佳选择。然而在 Froyo(2.2) 之前,HttpURLConnection 有个重大 Bug,调用 close() 函数会影响连接池,导致连接复用失效,所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive。另外在 2.3 HttpURLConnection 默认开启了 gzip 压缩,提高了 HTTPS 的性能, 4.0 HttpURLConnection 支持了请求结果缓存。所以综上所述,对 Android 来说,在 2.3 之后建议使用 HttpURLConnection,之前建议使用 AndroidHttpClient。

  2. Q: Volley在使用HttpClient进行网络请求时会设置User-Agent字段,而使用HttpURLConnection时则不会,原因是什么?
    A: 使用Fiddler/Charles抓包会发现,HttpURLConnection 默认是有 User-Agent 的,实际在请求发出之前,会检测 User-Agent 是否为空,如果为空,则加上系统默认 User-Agent。在 Android 2.1 之后,我们可以通过String userAgent = System.getProperty("http.agent")得到系统默认的 User-Agent。Volley 如果希望自定义 User-Agent,可在自定义 Request 中重写 getHeaders() 函数。
    在使用HttpClient进行网络请求时,Volley会将请求头中的 User-Agent 字段设置为 App 的 ${packageName}/${versionCode},如果异常则使用 "volley/0"(这个获取 User-Agent 的操作应该放到 if else 内部更合适)。

  3. Q: Volley中为什么使用ByteArrayPool进行存储网络数据?
    A: 首先可以试想一下ByteArrayPool产生的背景。当网络请求得到返回数据以后,我们需要在内存中开辟出一块区域来存放我们得到的网络数据,不论是json还是图片,都会存在于内存的某一块区域,然后拿到UI显示,然而移动客户端请求一般都是相当频繁的操作,想一下我们平时使用今日头条等一些客户端,几乎每一个操作都要进行网络请求。那么问题来了:这么频繁的数据请求,获得数据以后我们先要在堆内存开辟存储空间,然后显示,等到时机成熟,GC再回收这块区域,如此往复,那么GC的负担就会相当的重,然而Android客户端处理能力有限,频繁GC对客户端的性能是会产生很大的影响的。那么我们是否能够通过某种机制来减少内存分配次数和GC次数,从而达到提高程序性能的目的呢?我猜想这个问题便是这个类诞生的原因了。
    其次就需要看这个类是如何实现这样的目的的呢?从类名可以看出,这是一个字节数组缓存池,用来缓存从网络请求中获得的数据的。ByteArrayPool利用getBuf和returnBuf以及mBuffersByLastUse和mBuffersBySize来完成字节数组的缓存。当需要使内存区域的时候,先从已经分配的缓存区域中获得以减少内存分配次数。当空间用完以后,再将数据返回到此缓冲区。这样,就可以减少内存区域堆内存的波动和减少GC的回收,让CPU把更多的性能留给页面的渲染,提高性能。通过这个类发现,谷歌对技术的细节十分考究。

  4. Q: Volley为什么不适合用来下载大的数据文件?
    A: 因为Volley会在解析的过程中将所有的响应数据保留在内存中。对于下载大量数据的操作,请考虑使用DownloadManager。

  5. Q: 4. Volley的DiskBasedCache类会把服务器相应信息写入磁盘,然后再读磁盘取
    出缓存,writeInt(),writeLong()方法为什么要进行位运算?
    A: Java的IO本来就是对byte的操作,一个int占4个byte,所以需要按位写入。因为网络字节序是大端字节序,而在80X86平台中,是以小端法存放的,比如我们经过网络发送0x12345678这个整形,但实际上流是0x87654321。因为不同的平台int long等,他们的字节存储的顺序可能是不一样的。可能低位在前或者高位在前。writeInt() 和 readInt()以字节为单位,用一致的顺序读写,就能适配不同的平台。

  6. Q: RetryPolicy 如何做到重试的呢?具体流程是什么样的呢 ?
    A: 首先假设你设置了重试的策略,其次performRequest外面其实是个while 循环。假设在网络请求过程中产生异常, 比如read time out, catch 这个异常的代码会看看是否重试,如果是重试,就把这个异常吞掉,然后继续下一次循环,否则,抛出异常,由上一层代码去处理。

  7. Q: 当UI线程不断的向队列添加请求,队列如果有大小限制,队列满的时候不会ui线程阻塞么?如果没有大小限制,不会导致oom么?
    A: PriorityBlockingQueue:一个无界阻塞队列,PriorityBlockingQueue的默认容量是11;它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作。虽然此队列逻辑上是无界的,但是资源被耗尽时试图执行 add 操作也将失败(导致 OutOfMemoryError)。此类不允许使用 null 元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象(这样做会导致抛出 ClassCastException)。第一个问题:不会阻塞,只有获取的时候(如果队列为空,则会阻塞);第二个问题:会导致OOM。首先,volley里面用的BlockingQueue是PriorityBlockingQueue的实现类(队列定长11),这个类有个特点:不会阻塞调用者线程,所以UI线程不会被阻塞,这是第一个问题;第二个问题,有可能会导致堆内存溢出,所以使用这个实现类,还有个要求:调用者的生产速度不能快于处理者的处理速度。

  8. Q: CacheDispatcher和NetworkDispatcher两条线程都处理同一个Cache,难道不会出现互斥现象吗?为什么不加锁?
    A: 因为里边的方法都是同步的。

  9. Q: Volley实现网络缓存的机制?
    A: Volley的缓存方法:根据进行请求时服务器返回的缓存控制Header对请求结果进行缓存,下次请求时判断如果没有过期就直接使用缓存加快响应速度,如果需要会再次请求服务器进行刷新,如果服务器返回了304,表示请求的资源自上次请求缓存后还没有改变,这种情况就直接用缓存不用再次刷新页面,不过这要服务器支持了。当对上次的请求进行缓存后,在下次请求时即使没有网络也可以请求成功,关键的是,缓存的处理对用户完全是透明的,对于一些简单的情况会省去缓存相关的一些事情。

  10. Q: Volley中的设计模式
    A:

  1. Q: Volley的优点
    A:
上一篇 下一篇

猜你喜欢

热点阅读