Android實戰之你應該使用哪一個網絡庫?

本篇爲翻譯文章 原文地址這裏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客戶端: HttpURLConnectionApache 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 - 一個類型安全的HTTP客戶端支持REST接口

  • Picasso - 針對Android的圖片下載與緩存庫

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客戶端。

相關文章
相關標籤/搜索