Today almost every Android app uses HTTP/HTTPS requests as the main transport for transferring data. Even if you're not using HTTP directly, you may be using multiple SDKs that rely on HTTP for networking, such as analytics, crash reporting and ads.
So it's fair to say that HTTP is the ubiquitous, and perhaps even obvious, choice for data transfers. But choosing HTTP in Android should also include some consideration of the available libraries. Besides well known public APIs like HttpURLConnection or Apache Client, there are many great libraries to choose from. Why choose them? Because of the lengthy list of capabilities that alternative libraries may be better for, such as:
- ability to cancel network calls
- execute requests in parallel
- connection pooling to re-use existing socket connections
- local caching of responses
- simple async interface to avoid blocking in main or UI thread
- wrapping REST API calls
- retry policy and backoff
- efficiently load and transform images
- serializing through JSON
- support SPDY, HTTP/2.
It's a long list, but the older HTTP options have failed to keep up in many ways. The why and how of this state of affairs begins to make sense, once you know a bit of the history.
Google's HTTP Client Journey
In its early releases, Android only had the aforementioned public HTTP clients: HttpURLConnection and Apache HTTP Client. However, these were not implemented perfectly. While Google acknowledged that HttpURLConnection had some frustrating, unfixed bugs, like corrupting the connection pool when using close() in a readable InputStream, the company also stated that it didn't want to put more effort into Apache Client due to issues like the API's size.
The result, prior to Froyo, was fragmentation. Developers had to choose clients based on the OS version. This history can be seen in Google's Volley, where you can still find legacy workarounds that select a connection method based on the SDK version.
In 2013, Square attempted to address the fragmentation issue when it released OkHttp, a library built to work directly on a top of Java Socket without using any extra dependencies. To simplify the transition of existing code, Square implemented OkHttp using the popular HttpUrlConnection and Apache client interfaces.
OkHttp: More Than OK
Google eventually responded to widespread community support for OkHttp by making its 1.5 library part of Android 4.4 (KitKat). In 2015, Google followed up by deprecating the Apache-based AndroidHttpClient with the release of Android 5.1 (Lollipop).
Today, OkHttp v2.5.0 ships with a truckload of features, including:
- HTTP/2 and SPDY support allows all requests to the same host to share a socket
- Connection pooling reduces request latency (if SPDY isn't available)
- Transparent GZIP shrinks download sizes
- Response caching avoids the network completely for repeat requests
- Supports both synchronous blocking calls and async calls with callbacks.
- Supports WebSockets
- JavaRX compatible
My favorite part of OkHttp is its handy treatment of asynchronous requests, which divert processing away from the UI thread. In fact, starting from Android 3.0 (Honeycomb), it has been mandatory to perform network operations in a separate thread. In order to implement similar logic with HttpUrlConnection, you would have to come up with much bulkier design of using AsyncTask wrapper or separate Thread. It gets even more complicated if you need to support features like cancellation and connection pooling.
Google Returns Fire With Volley
At Google I/O 2013, the company responded to the popularity of OkHttp by launching Volley, an HTTP library that offered the following benefits:
- 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.
Everything in Volley sits on top of HttpUrlConnection. If you want to fetch images or JSON data, Volley has special abstractions: ImageRequest and JsonObjectRequest, which help to automatically convert HTTP payload. It's worth noting that Volley also uses a hardcoded networking thread pool size, while OkHttp opens a thread for each call and allows you to set the max size of the thread pool--so in certain cases OkHttp outperforms Volley, by utilizing more threads. There's even an HttpStack implementation which uses OkHttp's request/response API instead of HttpURLConnection within Volley, in case you want more threads.
HTTP clients have continued to evolve to support image-heavy apps, especially those which support infinite scroll and image transformations. At the same time, REST APIs have become industry standard, and every app developer has had to deal with boilerplate tasks such as JSON serializing and mapping REST calls to Java interfaces. These are three of the most popular options:
Retrofit is a type-safe HTTP client that provides a natural bridge between Java and REST. It quickly turns your HTTP API into a Java interfaces, and generates a self-documenting implementation. In addition, Retrofit also supports conversion to JSON, XML, protocol buffers.
Picasso, on the other hand, is specific to images, with a powerful HTTP image downloading and caching library. For example, you can load an image into your view with one line of code. Both Picasso and Retrofit are configurable to use OkHttpClient as the default HTTP client, but you can specify a HttpURLConnection-based client if you want. A similar library, Glide, provides additional features such as GIF animations, thumbnail generation, and still videos.
Facebook has its own open-source image library, Fresco, that it uses in its Android client. One of Fresco's key features is a custom memory allocation strategy for bitmaps to avoid costly garbage collector operations in JVM heap and JVM per-app memory limits. Fresco does this by allocating memory in Android called ashmem, which allows access from both Java and C++ code to perform all the CPU intensive transformations on the NDK level, and off of the UI thread. To save data and CPU, Fresco has three levels of cache: two in memory and another in internal storage.
The Options In Context
To display the relationships between the libraries, I created a diagram. As you can see, the HTTP transport component is interchangeable for the higher level libraries at the bottom of the diagram. You can choose between plain HttpUrlConnection or the latest OkHttpClient. In fact, we use exactly this capability in the PacketZoom Android SDK.
There have been attempts in the past to perform benchmarks between HTTP libraries, but this deserves a separate article. In the meantime, I hope this overview has given you an idea of the pros and cons of each library that will help you choose right one for your project.