本篇为翻译文章 原文地址这里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客户端。