Android实战之你应该使用哪个网络库?
前言
目前基本上每个应用都会使用HTTP/HTTPS协议来作为主要的传输协议来传输数据。即使你没有直接使用HTTP协议,也会有成堆的SDK会包含这些协议,譬如分析、Crash反馈等等。当然,目前也有很多优秀的HTTP的协议库,可以很方便的帮助开发者构建应用,本篇博文中会尽可能地涵盖这些要点。Android的开发者在选择一个合适的HTTP库时需要考虑很多的要点,譬如在使用Apache Client或者HttpURLConnection时可能会考虑:
能够取消现有的网络请求
能够并发请求
连接池能够复用存在的Socket连接
本地对于响应的缓存
简单的异步接口来避免主线程阻塞
对于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做了一个比较,其性能对比如下:
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" alt="" data-src="http://i.imgur.com/tIdZkl3.png" />
图片加载库对比
另一方面,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有三层不同的缓存:两层在内存中,以及一层在内部存储中。
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" alt="" data-src="https://scontent-lax3-1.xx.fbcdn.net/hphotos-xpt1/t39.2365-6/11057083_393469260836543_318035251_n.png" />
到现在,我发现应该把这些网络库的关系表述在一张图中。正如你可以看见的,HTTP的传输组件存在于示意图的底部,与所有上层的库进行交互。你可以选择单纯的HttpUrlConnection或者最新的OkHttpClient客户端。
Resources
- Square open source http://square.github.io
- Fresco library http://frescolib.org
- Volley documentation https://developer.android.com/training/volley
- Volley vs Retrofit http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit
- Picasso vs. Glide comparison
- StackOverflow thread on OkHTTP, Retrofit, Volley
- Jake Wharton presentations
原文:http://segmentfault.com/a/1190000003965158
https://packetzoom.com/blog/which-android-http-library-to-use.html
Android实战之你应该使用哪个网络库?的更多相关文章
- 【Android实战】----从Retrofit源代码分析到Java网络编程以及HTTP权威指南想到的
一.简单介绍 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明确为什么Retrofit那么屌. 近期也看了一些其源代码分析的文章以及亲自查看了源代码 ...
- [置顶]
【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的
一.简介 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明白为什么Retrofit那么屌.最近也看了一些其源码分析的文章以及亲自查看了源码,发现其对 ...
- 9套Android实战经典项目资料分享给大家
通过项目学习收获更大. 1.基于Android平台实战爱短信项目 下载地址:http://pan.baidu.com/s/1hr8CEry 2.Android平台实战CRM客户关系管理(AChartE ...
- Android实战技巧:深入解析AsyncTask
AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复. AsyncTask引发的一个问题 上 ...
- 【Android实战开发】3G技术和Android发展简介
随着移动设备的不断普及和发展,相关软件的开发也越来越受到人们的关注,其中要提及的就是Android开发.本系列博客主要为大家介绍Android的开发,可能会有人问:现在互联网上已经有很多的Androi ...
- 【Android实战】记录自学自己定义GifView过程,能同一时候支持gif和其它图片!【有用篇】
之前写了一篇博客.<[Android实战]记录自学自己定义GifView过程,具体解释属性那些事! [学习篇]> 关于自己定义GifView的,具体解说了学习过程及遇到的一些类的解释,然后 ...
- Android实战:手把手实现“捧腹网”APP(二)-----捧腹APP原型设计、实现框架选取
Android实战:手把手实现"捧腹网"APP(一)-–捧腹网网页分析.数据获取 Android实战:手把手实现"捧腹网"APP(二)-–捧腹APP原型设计.实 ...
- Android实战:手把手实现“捧腹网”APP(一)-----捧腹网网页分析、数据获取
Android实战:手把手实现"捧腹网"APP(一)-–捧腹网网页分析.数据获取 Android实战:手把手实现"捧腹网"APP(二)-–捧腹APP原型设计.实 ...
- 利用百度词典API和Volley网络库开发的android词典应用
关于百度词典API的说明,地址在这里:百度词典API介绍 关于android网络库Volley的介绍说明,地址在这里:Android网络通信库Volley 首先我们看下大体的界面布局!
随机推荐
- IE6下Png透明最佳解决方案(推荐) Unit PNG Fix
引自:http://www.yeeyan.org/articles/view/98510/67784 网络上解决IE6下Png透明解决方案有很多,例如 IE PNG Fix from TwinHeli ...
- javascript-02
1.js的特点2.js的数据类型3.js运算符 4.js的全局变量 |-定义在函数体外部的变量 |-定义在函数体内部没有使用var声明 var和没有var声明变量的区别? |-var ...
- pull解析xml文件
pull解析xml文件 先自己写一个xml文件,存一些天气信息 拿到xml文件 InputStream is = getClassLoader().getResourceAsStream(" ...
- java swing窗口放置屏幕中央问题思考
java swing窗口放置屏幕中央问题思考 以前总是尝试各种方法都没有能把组件放到屏幕中央,只能用死办法,设置绝对坐标,但这样就失去了可移植性,而且繁琐.今天仔细思考了一番,终于被我找出问题所在. ...
- objective-c中是如何实现线程同步的?
多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美.这篇文章主要从线程创建与启动.线程的同步与锁.线程的交互.线 ...
- maven使用之烦人的.lastUpdated文件
项目使用maven管理jar包,很容易因为各种原因(网速慢.断网)导致jar包下载不下来,出现很多.lastUpdated文件.这些文件一个一个删除太麻烦.下面是全部删除的方法 windows系统 c ...
- STL库之单链表:forward_list
class template forward_list <forward_list> template < class T, class Alloc = allocator<T ...
- 基于jQuery的图片左右轮播,基本原理通用
毕竟新人,写点基础的小东西,希望能和大家沟通交流,提高自己的水平. 这个是应用较多的轮播部分,希望能和大家分享一下思路,拓宽视野. 话不多说,上内容. 我的思路很简单就是通过判断index值的大小变化 ...
- 网站开发常用jQuery插件总结(11)折叠插件Akordeon
实现折叠菜单,可以完全不使用插件.如果使用jquery的话,实现起来也比较简单,我们只需要定义折叠菜单的样式,然后使用jquery中的渐隐渐现就可以了.如果我们自己写折叠菜单,可以方便的使用我们自己的 ...
- 使用Unidac内置连接池
第一步: 放一个TUniconnection并设置相关属性 之后直接使用TUniconnection对象即可 跟踪unidac源码uni单元1540行中可以看到 Connect方法调用CreateIC ...