Android的HTTP客户端接口 [整理]

bitmapfun项目  看到一个函数[在使用HttpURLConnection下载之前调用]:

 /**
     * Workaround for bug pre-Froyo, see here for more info:
     * http://android-developers.blogspot.com/2011/09/androids-http-clients.html
     */
    public static void disableConnectionReuseIfNecessary() {
        // HTTP connection reuse which was buggy pre-froyo
        if (hasHttpConnectionBug()) {
            System.setProperty("http.keepAlive", "false");
        }
    }


/**
     * Check if OS version has a http URLConnection bug. See here for more information:
     * http://android-developers.blogspot.com/2011/09/androids-http-clients.html
     *
     * @return
     */
    public static boolean hasHttpConnectionBug() {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO;
    }


说是android 2.2之前HttpURLConnection 存在的bug,, 当你在可读取的InputStream上调用 close()函数的时候会 污染连接池 (connection pool).  可以通过禁用连接池的方法还解决这个问题。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

大多数需要网络连接的Android应用都会使用HTTP来传输数据。Android自带了两个HTTP客户端:HttpURLConnection和Apache HTTP Clinent。它们都支持HTTPS,文件上传下载,配置超时,IPV6及连接池。

Apache HTTP Client

DefaultHttpClient 及其相似的 AndroidHttpClient 都是HttpClient的扩展适用于Web浏览器。它们有丰富的可扩展的API,同时也很稳定没有什么Bug。但是这里重量级的API让我们难以修改后保证它的兼容性,因为Android团队并没有负责Apache HTTP Client 的开发和维护!

HttpURLConnection

HttpURLConnection是一个通用的,轻量级的适用于绝大多数应用的HTTP客户端。这个类比较底层,但我们可以很容易的稳步修改它的关键的API。

在Froyo(2.2)之前,HttpURLConnection有几个烦人的Bug,特别是,在一个可读的InputStream中调用close()会

污染连接池,一个解决方案就是在低android版本中禁用连接池。

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)这个版本中, Dalvik团队又添加了自动压缩数据的功能. 当你调用HttpURLConnection的时候,它会自动的添加gzip属性到请求头中,并且会自己解压返回的数据, 开发者完全不用为了处理压缩数据而增加工作量, 只要服务器配置支持gzip就行了:
Accept-Encoding: gzip

如果你发现服务器返回的压缩数据有问题,可以参考HttpURLConnection的文档来禁用该功能!

因为HTTP客户端的Content-Length头部返回的是压缩后的大小,所以使用getContentLength()来获得解压后的数据块的大小是错误的。你应该从响应中读取字节直到InputStream.read()返回-1。


同时我们对在Gingerbread中的HTTPS连接做了一些优化,当HttpsURLConnection尝试连接SNI(Server Name Indication)将允许多个hosts共享一个IP地址。同样支持压缩和Session tickets。如果连接失败,将自动重试(it is automatically retried without these features)。这使得HttpURLConnection在连接新的服务器时更有效,同时不破坏向下兼容。

在Ice Cream Sandwich(4.X)中,我们添加了响应缓存。有了缓存,HTTP请求就会满足下面三种方式:

 (1)完全缓存的响应将直接从本地存在中获得。因为无需进行网络连接 ,这样的响应可以马上获得。

 (2)条件缓存的响应必须到服务器验证是否过期,客户端发送一个请求如"给我 /foo.png 如果从昨天后发生了改变的话",然后服务器响应返回更新的内容 或者一个304 Not Modified状态。如果内容没有更新,则将不会下载 。

 (3)非缓存的响应将从web端获得,这些请求会存储在响应缓存中以务后用。


可以利用反射来在支持的设备中开启HTTP 响应缓存 。下面的代码将在4.0之后的版本的开启响应缓存 。而不会影响之前的版本。


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响应中设置缓存头部。

哪一个客户端最好?

在Eclair(2.1)和Froyo(2.2)中,Apache HTTP Client(相比HttpURLConnection)没有什么Bug,

对于这些发行版,它是最好的选择。

对于 Gingerbread(2.3)及之后的版本。HttpURLConnection是最好的选择。它的简单轻量最适合android。

压缩,缓存响应以减少网络连接,提升速度,省电,新的应用应该使用HttpURLConnection,它也是我们将来的着力点。




你可能感兴趣的:(Android的HTTP客户端接口 [整理])