关于 Android 中的 HTTP Clients

本文翻译自 Google Dalvik 虚拟机团队 Jesse WilsonAndroid’s HTTP Client

绝大多数 Android app 都会用 HTTP 来进行网络连接,已达到收发数据的目的。 Android 中有两个 Http 使用类,分别是:

  • 1.HttpURLConnection.
  • 2.Apache 的 HTTP Client.

这两种都支持 HTTPS,上传,下载,超时配置,IPv6 和连接池。

Apache HTTP Client

DefaultHttpClient 和他的兄弟类 AndroidHttpClient 对于 web 浏览器拓展性非常好。它们拥有庞大的,弹性很好的 API 供我们使用。且它们稳定性极高,很少存在 bug.

但是如此大量的 API,在我们不破坏其兼容性的前提下,很难去对其拓展。这也是为什么 Android 团队为何不喜欢 Apache HTTP Client 的原因。

HttpURLConnection

HttpURLConnection 是一个比较通用的,轻量级的,适用于大多数应用的 HTTP 类.我们很容易在此类上做拓展。

在 Froyo(2.2)之前, HttpURLConnedction 存在一个重大 bug.那就是,在对 InputStream 调用 close() 方法时会影响连接池。所以在 2.2 之前我们需要关闭连接池:

1
2
3
4
5
6
private void disableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}

在 Gingerbread(2.3)版本上,为 HttpURLConnection 添加了 gzip 压缩请求头:

Accept-Encoding: gzip

利用它,可以让服务端对传输的数据进行压缩,如果对压缩的支持有问题的话,你可以参考这里的文档,以便知道如何来禁用此项功能。

通过 HTTP 的 Content-Length 头来获取压缩文件的大小。使用 getContentLength() 来获取未压缩数据的大小是错误的。正确的做法是,从服务端读取字节流直到 InputStream.read() 返回 -1 为止。

我们在 Gingerbread(2.3) 中对 HTTPS 做了些许改进。 HttpURLConnection 能够尝试连接 Server Name Indication(SNI:允许多个HTTPS主机共享一个IP地址).此外, HttpURLConnection 还有压缩数据和获取 session 的功能。 如果连接失败,HttpURLConnection 会禁用掉这些功能然后再次连接。 这使得 HttpURLConnection 在不破坏对旧版本兼容性的基础上,能够根据服务端的实际情况来选择最高效的应对方案。

在 Ice Cream Sandwich(4.0)中, 我们添加了请求结果缓存的功能. 一旦有了缓存, HTTP 请求将会在下面三种方式中挑选:

  • 在没有网络连接的情况下,且本地有完整缓存的时候,HTTP 请求会直接从本地拿数据。
  • 局部数据缓存需要向服务器验证本地缓存是否为服务器上最新的数据。比如说:客户端发了一条类似这样的请求:”给我一张本地在昨天有缓存的 foo.png 的图片”,这时服务器可能会返回两种结果,一是被更新过的这张图片,或者是 304(未被更新,可以直接拿本地数据)。也就是说,如果图片没被更新过,则不会再次下载图片。
  • 本地没有缓存的数据会请求服务器拿最新的。稍后,它们将会被缓存。

我们可以在支持缓存的设备上来打开 HTTP 的缓存功能。下面的实例告诉你如何在不影响 Ice Cream Sandwich(4.0)前的版本上来打开这项功能:

1
2
3
4
5
6
7
8
9
10
private void enableHttpResponseCache() {
try {
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
File httpCacheDir = new File(getCacheDir(), "http");
Class.forName("android.net.http.HttpResponseCache")
.getMethod("install", File.class, long.class)
.invoke(null, httpCacheDir, httpCacheSize);
} catch (Exception httpResponseCacheNotAvailable) {
}
}

你需要同时在服务端在对 HTTP 做响应时,配置缓存头(cache headers).

我们应该如何抉择

在 Froyo(2.2) 之前,我们最好选择 Apache 的 HTTP client。
在 Gingerbread(2.3) 之后, HttpURLConnection 是最好的选择。 它的轻量化使得它非常适合 Android, 另外,数据压缩和请求结果缓存使得它的性能大幅提高(包括响应速度,节省电量)。

文章有帮助到您?不妨打赏博主一碗拉面或一杯咖啡的小费吧 :-D!