月度归档:2017年03月

Volley 简析

Volley 是 Google 为了让 Android apps 的网络请求更加容易和快速而推出的 HTTP 库。

Github 地址:https://github.com/google/volley

Training 地址:https://developer.android.com/training/volley/index.html

请求流程

这是官网贴的一张说明 request 如何被执行的流程图。

简单介绍一下就是:

  1. 在 main thread 发起带有优先级区分的 request;
  2. 在 main thread 中将 request 添加到一个具有优先级区分缓存请求队列 CacheQueue中;
  3. 在 cache thread 取出 CacheQueue 中优先级最高的 request,在 cache 中查找对应的 reponse。
    1. 如果有 cache 被命中,将 response 传递给 response delivery;
    2. 如果没有 cache 被命中(包含 cache 已过期等情况),将该 request 加入同样具有优先级区分的网络请求队列 NetworkQueue 中;
  4. 在 network threads 中取出 NetworkQueue 中优先级最高的 request,进行网络请求,获取 response,并传递给 response delivery;
  5. response delivery 将 response 转发回 main thread。

整体感觉就是 Volley 在维护几个 Request 的队列和集合,针对这几个 Queue 和 Set 分别绑定了相应的处理器,Volley 这台控制器只负责调度 Request 在这几个 Queue 和 Set 中进行传递。

Features

下面主要记录一些网络上的源码解析文章中没有提到的点:

  1. Request 的去向

    Volley 中的有四个请求队列或者集合分别是:

    1. CurrentRequests: cancelAll 时遍历 requests;
    2. WaitingRequests: 避免重复网络请求;
    3. CacheQueue: 需要在缓存中查找的请求队列;
    4. NetworkQueue : 需要通过网络获取的请求队列;
  2. Request cancel 的实现

    cancel 方法中将 Request 中的标记位设置为 True,然后再 Request 处理的各个环节提前进行检测,如果发现该 Request 已被 cancel 就直接返回。其中的各个环节包括:

    1. CacheDispatcher 查找缓存之前;
    2. NetworkDispatcher 进行网络请求之前;
    3. ExecutorDelivery 转发 Response 之前;

    这样最大限度确保 Request 能及时被 cancel 掉。

  3. Cache

    缓存接口,定义了实现缓存需要的各个方法;

  4. Network

    网络接口,定义了实现网络请求需要的各个方法,整个 Volley 中到处都是针对类似的接口编程,使得非常容易进行扩展,实现自定义的 Request、Cache、Network 等模块;

  5. ExcutorDelivery

    将结果传递到主线程

  6. request FIFO

    1. 根据 Priority (LOW < NORMAL < HIGH < IMMEDIATE) 判别
    2. Request 被 add 的时候 setSequence,该值每添加一个就 + 1,先入列的值小
    3. RequestQueue 是一个 PriorityBlockingQueue,该队列的元素需要实现 Comparable 接口,该接口会比较 Priority 值。如果不同,依据 Priority;相同时比较 sequence 的值。take 元素时会根据比较结果取出优先级最高的值
  7. toolbox

    toolbox 中是 Volley 中各接口的默认实现,比如 Network、Cache、Request 等,其中还包含一个自定义 View — NetworkImageView

  8. NetworkImageView

    该 View 在 Volley 发布会上有被提到,特殊之处在于可以避免在快速滑动时进行图片的请求和加载

参考

  1. Volley 源码解析 http://p.codekk.com/blogs/detail/54cfab086c4761e5001b2542
  2. Android网络框架源码分析——Volley http://www.jianshu.com/p/9e17727f31a1

ASCII & Unicode & UTF-8

转载自 字符串和编码

因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295

由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122

但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和 ASCII 编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。

你可以想得到的是,全世界有上百种语言,日本把e日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

因此,Unicode 应运而生。Unicode 把所有语言都统一到一套编码里,这样就不会再有乱码问题了。

Unicode 标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持 Unicode。

现在,捋一捋 ASCII 编码和 Unicode 编码的区别:ASCII 编码是1个字节,而 Unicode 编码通常是2个字节。

字母A用 ASCII 编码是十进制的65,二进制的01000001

字符0用 ASCII 编码是十进制的48,二进制的00110000,注意字符'0'和整数0是不同的;

汉字已经超出了 ASCII 编码的范围,用 Unicode 编码是十进制的20013,二进制的01001110 00101101

你可以猜测,如果把 ASCII 编码的A用 Unicode 编码,只需要在前面补0就可以,因此,A的 Unicode 编码是00000000 01000001

新的问题又出现了:如果统一成 Unicode 编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用 Unicode 编码比 ASCII 编码需要多一倍的存储空间,在存储和传输上就十分不划算。

所以,本着节约的精神,又出现了把 Unicode 编码转化为“可变长编码”的UTF-8编码。UTF-8 编码把一个 Unicode 字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用 UTF-8 编码就能节省空间:

字符 ASCII Unicode UTF-8
A 01000001 00000000 01000001 01000001
x 01001110 00101101 11100100 10111000 10101101

从上面的表格还可以发现,UTF-8 编码有一个额外的好处,就是 ASCII 编码实际上可以被看成是 UTF-8 编码的一部分,所以,大量只支持 ASCII 编码的历史遗留软件可以在 UTF-8 编码下继续工作。

搞清楚了 ASCII、Unicode和 UTF-8 的关系,我们就可以总结一下现在计算机系统通用的字符编码工作方式:

在计算机内存中,统一使用 Unicode 编码,当需要保存到硬盘或者需要传输的时候,就转换为 UTF-8 编码。

用记事本编辑的时候,从文件读取的 UTF-8 字符被转换为 Unicode 字符到内存里,编辑完成后,保存的时候再把 Unicode 转换为 UTF-8 保存到文件:

浏览网页的时候,服务器会把动态生成的 Unicode 内容转换为 UTF-8 再传输到浏览器:

所以你看到很多网页的源码上会有类似<meta charset="UTF-8" />的信息,表示该网页正是用的 UTF-8 编码。

清除 Android 未使用的资源文件

其实很简单,Android Studio 自带了这个工具。具体使用方式为:

  1. 在 module 上右击,选择 Refactor -> Remove Unused Resources:

  1. 选择 Preview 预览:

  1. 选择 Do Refactor 进行删除:

  1. 在 3 中没找到选择删除的方法,因此可以在全部删除之后,通过 git 恢复不需要删除的资源文件。