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 - 一个类型安全的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客户端。

Resources

  1. Square open source http://square.github.io
  2. Fresco library http://frescolib.org
  3. Volley documentation https://developer.android.com/training/volley
  4. Volley vs Retrofit http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit
  5. Picasso vs. Glide comparison
  6. StackOverflow thread on OkHTTP, Retrofit, Volley
  7. Jake Wharton presentations

原文:http://segmentfault.com/a/1190000003965158

https://packetzoom.com/blog/which-android-http-library-to-use.html

时间: 2024-10-05 13:19:19

Android实战之你应该使用哪个网络库?的相关文章

Android实战——jsoup实现网络爬虫,糗事百科项目的起步

Android实战--jsoup实现网络爬虫,爬糗事百科主界面 本篇文章包括以下内容: 前言 jsoup的简介 jsoup的配置 jsoup的使用 结语 前言 对于Android初学者想要做项目时,最大的烦恼是什么?毫无疑问是数据源的缺乏,当然可以选择第三方接口提供数据,也可以使用网络爬虫获取数据,这样就不用第三方数据作为支持.本来是打算爬一些购物网站的数据,由于他们的反爬做得好,所以没办法爬到数据,只能爬取糗事百科的数据,或许聪明的你会想到可以高仿个糗事百科作为自己的练手项目,利用jsoup是

【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的

一.简介 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明白为什么Retrofit那么屌.最近也看了一些其源码分析的文章以及亲自查看了源码,发现其对Java网络编程及HTTP权威指南有了一个很好的诠释.一直以来,都信奉一个原则,在这个新技术日新月异的时代,如何在Java界立足,凭借的就两点: 1.基本功,包括:Java基本知识,(Java编程思想.Effective Java),Java进阶(Java虚拟机.Java设计模式).网络相关(这个时

android实战网址

10套Android实战经典资料分享 收集了10套Android学习资料,分享给大家,希望对学习这方面的朋友有帮助 1.实战Android手机客户端的家校通平台V1.0(SurfaceView实现统计图表)下载地址:http://pan.baidu.com/share/link?shareid=3121570264&uk=506606919&third=15 2.基于智能手机Android平台音乐播放器全程开发实战下载地址:http://pan.baidu.com/share/link?s

【Android实战】记录自学自己定义GifView过程,能同一时候支持gif和其它图片!【有用篇】

之前写了一篇博客.<[Android实战]记录自学自己定义GifView过程,具体解释属性那些事! [学习篇]> 关于自己定义GifView的,具体解说了学习过程及遇到的一些类的解释,然后完毕了一个项目,能通过在xml增加自己定义 view (MyGifView)中增加自己定义属性(my:gif_src = "@drawable/coffee").达到播放gif图片的效果. 可是.有几个问题 1.gif_src 属性仅仅支持 gif 图,并不支持其它类型的图片 2.仅仅支持

Android实战技巧:深入解析AsyncTask

AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复. AsyncTask引发的一个问题 上周遇到了一个极其诡异的问题,一个小功能从网络上下载一个图片,然后放到ImageView中,是用AsyncTask来实现的,本身逻辑也很简单,仅是在doInBackground中用HTTP请求把图片的输入流取出,然后用BitmapFactory去解析,然后再把得到的Bitmap放到ImageView中

Android实战简易教程-第二十五枪(基于Baas的数据表查询下拉刷新和上拉加载实现!)

上一节我们实现了数据表的加载,但是,当数据表数据很多时,我们就要考虑数据的分页,这里我们选用了PullToRefreshListView控件,先看一下该控件的说明: 效果图:                                 正在刷新                                                                       刷新后        一.导入Library 下载源码后(https://github.com/chrisba

Android实战——RxJava2解锁图片三级缓存框架

RxJava2解锁图片三级缓存框架 本篇文章包括以下内容 前言 图片三级缓存的介绍 框架结构目录的介绍 构建项目整体框架 实现图片三级缓存 演示效果 源码下载 结语 前言 RxJava2作为如今那么主流的技术,不学习学习都不行了,本篇文章需要你有RxJava2的基础,如果需要对RxJava2学习的同学,可以关注我的博客,查看Android实战--RxJava2+Retrofit+RxBinding解锁各种新姿势 .项目代码实现模仿Picasso,大伙们可以看下最后的代码效果,那么废话不多说,He

跨平台:GN实践详解(ninja, 编译, windows/mac/android实战)

跨平台:GN实践详解(ninja, 编译, windows/mac/android实战)展开目录一.概览二.跨平台代码编辑器三.GN入门四.示范工程五.关键细节六.结语 [编译器选项] 其中前两部分是前缀部分,原本没有跨平台构建经验和知识的同学可以借助来帮助理解,后四部分则是讲述GN工程的基本结构.如何搭建一个GN构建的工程.以及关键的一些GN知识 一.概览如何开始这个话题是我比较在意的,因为对于部分人而言,真正从思维和理解上切入这篇文章真正要阐述的点是有困难的.这在于跨平台编译和开发这块,如果

【Android实战】记录自学自定义GifView过程,能同时支持gif和其他图片!【实用篇】

之前写了一篇博客,<[Android实战]记录自学自定义GifView过程,详解属性那些事![学习篇]> 关于自定义GifView的,详细讲解了学习过程及遇到的一些类的解释,然后完成了一个项目,能通过在xml加入自定义 view (MyGifView)中加入自定义属性(my:gif_src = "@drawable/coffee"),达到播放gif图片的效果. 但是,有几个问题 1.gif_src 属性只支持 gif 图,并不支持其他类型的图片 2.只支持默认的引用图片,不