本篇爲翻譯文章 原文地址這裏html
若是正在學習Android,建議能夠參考筆者的個人編程之路——知識管理與知識體系java
[TOC]android
目前基本上每一個應用都會使用HTTP/HTTPS協議來做爲主要的傳輸協議來傳輸數據。即便你沒有直接使用HTTP協議,也會有成堆的SDK會包含這些協議,譬如分析、Crash反饋等等。固然,目前也有不少優秀的HTTP的協議庫,能夠很方便的幫助開發者構建應用,本篇博文中會盡量地涵蓋這些要點。Android的開發者在選擇一個合適的HTTP庫時須要考慮不少的要點,譬如在使用Apache Client或者HttpURLConnection時可能會考慮:git
可以取消現有的網絡請求github
可以併發請求編程
鏈接池可以複用存在的Socket鏈接segmentfault
本地對於響應的緩存api
簡單的異步接口來避免主線程阻塞緩存
對於REST API的封裝安全
重連策略
可以有效地載入與傳輸圖片
支持對於JSON的序列化
支持SPDY、HTTP/2
最先的時候Android只有兩個主要的HTTP客戶端: HttpURLConnection, Apache HTTP Client。根據Google官方博客的內容,HttpURLConnection在早期的Android版本中可能存在一些Bug:
在Froyo版本以前,HttpURLConnection包含了一些很噁心的錯誤。特別是對於關閉可讀的InputStream時候可能會污染整個鏈接池。
一樣,Google官方並不想轉到Apache HTTP Client中:
Apache HTTP Client中複雜的API設計讓人們根本不想用它,Android團隊並不可以有效地工做。
而對於大部分普通開發者而言,它們以爲應該根據不一樣的版本使用不一樣的客戶端。對於Gingerbread(2.3)以及以後的版本,HttpURLConnection會是最佳的選擇,它的API更簡單而且體積更小。透明壓縮與數據緩存能夠減小網絡壓力,提高速度而且可以節約電量。當咱們審視Google Volley的源代碼的時候,能夠看得出來它也是根據不一樣的Android版本選擇了不一樣的底層的網絡請求庫:
if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } }
不過這樣會很讓開發者頭疼,2013年,Square爲了解決這種分裂的問題發佈了OkHttp。OkHttp是直接架構與Java Socket自己而沒有依賴於其餘第三方庫,所以開發者能夠直接用在JVM中,而不只僅是Android。爲了簡化代碼遷移速度,OkHttp也實現了相似於HttpUrlConnection與Apache Client的接口。
OkHttp得到了巨大的社區的支持,以致於Google最終是將它做爲了Android 4.4默認的Engine,而且會在5.1以後棄用Apache Client。目前OkHttp V2.5.0支持以下特性:
HTTP/2 以及 SPDY的支持多路複用
鏈接池會下降併發鏈接數
透明GZIP加密減小下載體積
響應緩存避免大量重複請求
同時支持同步的阻塞式調用與異步回調式調用
筆者關於OkHttp最喜歡的一點是它可以將異步請求較好的展現:
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, Throwable throwable) { throwable.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string()); } }); }
這個用起來很是方便,由於每每大的數據請求都不能放置在UI主線程中進行。事實上,從Android 3.0(Honeycomb 11)開始,全部的網絡操做都必須強制在單獨的線程中進行。在當時若是要把HttpUrlConnection和AsyncTask結合起來使用,仍是比較複雜的。而2013年的Google I/O大會上,Google提出了Volley,一個提供了以下便利的HTTP庫:
Automatic scheduling of network requests.
Multiple concurrent network connections.
Transparent disk and memory response caching with standard HTTP cache coherence.
Support for request prioritization.
Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.
Ease of customization, for example, for retry and backoff.
Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.
Debugging and tracing tools.
Volley主要架構在HttpUrlConnection之上,若是但願可以抓取圖片或者JSON數據,Volley有自定義的抽象類型ImageRequest與JsonObjectRequest,能夠自動轉化爲HTTP請求。同時,Volley也有一個硬編碼的網絡鏈接池大小:
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
不過OkHttp能夠自定義鏈接池的大小:
private int maxRequests = 64; private int maxRequestsPerHost = 5; executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
在某些狀況下,OkHttp能夠經過使用多線程來有更好的性能體現。不過若是現有的程序中已經用Volley作了頂層封裝,那麼也可使用HttpStack implementation這個來使用OkHttp的請求與響應接口來替換HttpUrlConnection。
到這裏已經能夠發現,OkHttp本質上是自定義了一套底層的網絡請求架構。目前HTTP客戶端已經逐步轉化爲了支持大量圖片,特別是那種無限滾動與圖片傳輸的應用。同時,REST API已經成爲了業界標準,基本上每位開發者都須要處理大量標準化的任務,相似於JSON序列化與將REST請求映射到Java的接口上。Square也在不久以後針對這兩個問題提出了本身的解決方案:
Retrofit 提供了一個面向Java代碼與REST接口之間的橋接,能夠迅速將HTTP API轉化到Java接口中而且自動生成帶有完整文檔的實現:
public interface GitHubService { @GET("/users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); GitHubService service = retrofit.create(GitHubService.class);
除此以外,Retrofit 也支持面向JSON、XML以及Protocol Buffers的數據轉化。在另外一篇博客中將AsyncTask與Volley以及Retrofit作了一個比較,其性能對好比下:
另外一方面,Picasso是一個專門的面向圖片任務的HTTP庫。譬如,能夠用一行代碼就把網絡圖片加載到ImageView中:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Picasso與Retrofit都是默認的使用OkHttpClient做爲底層的HTTP客戶端,然而,你也能夠配置本身的基於HttpUrlConnection的客戶端。
Glide是一個很是相似於Picasso的庫,不過它提供了一些額外的功能,譬如GIF動畫、簡略圖生成以及視頻。
Facebook開源的它們本身的圖片加載庫Fresco使用了它們自定義的Android客戶端。其中它的一個很是優秀的特性在於Fresco的面向Bitmaps的自定義才存儲策略可以避免JVM堆頂的垃圾回收的限制。Fresco是分配了Android中被稱爲ashmem部分的內存,同時,它用了一些方法容許同時從Java以及C++代碼訪問ashmem部分,來進行NDK級別的CPU處理。爲了節省數據存儲空間以及CPU的消耗,Fresco有三層不一樣的緩存:兩層在內存中,以及一層在內部存儲中。
到如今,我發現應該把這些網絡庫的關係表述在一張圖中。正如你能夠看見的,HTTP的傳輸組件存在於示意圖的底部,與全部上層的庫進行交互。你能夠選擇單純的HttpUrlConnection或者最新的OkHttpClient客戶端。