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,它也是我們將來的着力點。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章