网易考拉Android客户端网络模块设计

本文来自网易云社区html

做者:王鲁才nginx


客户端开发中不可避免的须要接触到访问网络的需求,如何把访问网络模块设计的更具备扩展性是每个移动开发者不得不面对的事情。如今有不少主流的网络请求处理框架,如Square公司的OkHttp,Google推出的Volley,还有在OkHttp基础上进行封装的Retrofit等,这些都是很是优秀的网络处理框架。利用现有网络处理框架,比从零开始设计、开发网络请求节省不少开发时间,同时也避免了一些意想不到的问题。若是把这些框架直接拿来使用,不进行任何二次封装,会使咱们工程层次结构不清晰(数据存取、逻辑处理、UI展现),不利于扩展(替换成其余网络框架)。因此选择一个合适的网络框架并进行封装,这在开发过程当中是很是必要的。django

1.   概述

   一般状况下,客户端数据流遵循以下图所述方式流动,UI层负责展现数据,接收用户操做;逻辑处理层处理用户操做,并将处理结果反馈给UI层进行展现;数据层负责数据存取,这里可能会涉及多种方式存取数据:本地缓存中存取数据,向服务器请求存取数据;网络访问层负责从服务器存取数据,数据返回后进行解析,并将结果返回给数据存取层。缓存

2.   考拉Android客户端网络模块设计

下面简要介绍一下考拉Android客户端网络模块设计的变迁历程,在这个过程当中咱们也踩了很多坑,好在咱们把这些坑都填平了,并且正在朝着更好的方向发展。服务器

在考拉项目开始之初,咱们对比了Volley、OKHttp等主流网络处理框架,最终选择了Volley做为考拉Android客户端的网络请求模块。Volley是在2013年IO大会上Google推出的异步网络请求框架(和图片加载框架),特别适合数据量小,通讯频繁的网络操做。网络

2.1 存在的问题

1.      封装扩展性差(SPDY,HTTPS);数据结构

2.      存在内存泄漏(Volley本身的问题);框架

3.      数据解析在UI线程中进行,阻塞UI展现;异步

在这一版本的网络请求封装中存在一个比较严重的问题,数据解析在UI线程中进行,在最初的几个版本中,请求的数据量较小,UI比较简单,阻塞UI线程的这个问题还不是特别明显,可是随着UI愈来愈复杂,同时请求数据、解析数据的操做也愈来愈多,阻塞UI线程解析数据,存在丢帧问题。为了解决这个问题,引入了工做线程池,网络请求回来之后,先将数据返回给调用者(UI线程),调用者在解析数据的时候,开启工做线程,数据解析完成后再抛回UI线程,UI线程进行数据展现。在这个过程当中,有屡次线程切换,线程建立、切换、调度都是须要内存、时间开销的。更要命的是,这个过程对调用者不透明,调用者必须知道当前操做是在哪一个线程中进行的。微服务

扩展性差这一点相信不少开发者都有比较痛的感悟。为了兼容不一样服务器返回的不一样数据格式,在网络请求模块中定义了不少不一样参数的回调方法。在请求数据时,每一种回调接口都要对应一个具体的方法(传入的回调接口不一样),代码写的比较冗余,条理性、扩展性差,简直要不能直视了。

2.2 重构

为了解决上面两个问题,对网络请求模块进行了重构,引入了泛型数据,从新定义了网络数据返回结构,新增了数据解析器。根据用户传入的不一样解析器,将网络返回数据解析成不一样类型。在网络数据返回后,直接将数据解析操做从UI线程中抛到工做线程中,这个过程对调用者是透明的。调用者只须要知道网络请求操做和数据解析操做是在工做线程中进行的,回调接口在UI线程中执行就能够。

在这个网络响应回调接口中,采用了泛型,调用者能够返回任意数据结构,为了提升兼容性,在错误回调方法中,不只传入了错误码和错误缘由,并且还额外增长了一个Object类型的数据,供调用者返回其余数据信息。

KoalaStringParser是通用数据解析接口,主要针对有特殊需求的数据解析;对于通用的、与服务器约定好的数据返回格式,能够继承KoalaSimpleStringParser抽象类,实现onSimpleParse抽象方法解析数据。通用数据解析接口和抽象数据解析类,既保证了扩展性,又对通用数据格式有了统一处理。

2.3 数据缓存

若是不考虑数据缓存的话,上面对网络请求的封装基本也能知足咱们的要求了。可是若是没有数据缓存,每次都向服务器请求数据,启动新页面,会有时间长短不一的加载过程,没有网络或者网络很差时,会显示一个空白页面告诉用户网络不可用,这下降了用户体验。为了提高用户体验,减小启动页面的等待时间,增长数据缓存是一件颇有必要的事情。缓存能够与服务器配合,使用HTTP的缓存机制,也能够在客户端单独使用。由于如今考拉服务器尚未支持缓存,现阶段只能在客户端添加缓存。

上面是在没有服务器支持的状况下,客户端支持的缓存。在启动页面请求数据时,先判断是否容许读取缓存数据。容许读取缓存数据,检查是否存在缓存数据,存在缓存数据,将数据从本地缓存中读取后直接返回给调用者;不存在缓存数据,不作任何处理。在检查缓存数据时,同时向服务器发送请求,获取数据,数据返回后更新缓存数据。这里须要注意的是,回调接口可能会被调用两次,一次是从缓存读取数据的回调,一次是从服务器读取数据的回调。出现两次回调的问题,须要调用者进行区分,在回调方法中添加了当前回调是从本地读取数据的回调仍是从网络读取数据的回调标示。

         服务端不支持缓存,只在客户端对数据进行缓存处理,在必定程度上提高了用户体验,避免用户屡次请求相同页面时出现屡次重复加载、长时间等待的问题。这种缓存方式并不能节省用户流量。

2.4 切换到OkHttp

前一段时间项目组提到考拉可能会引入SPDY来优化性能,后面为了解决劫持问题,还可能会上HTTPS,考虑到OkHttp已经内置了对SPDY的支持,并且对HTTPS的封装比较好,未雨绸缪,咱们决定从Volley转投OkHttp了,由于以前已经对网络请求进行了封装,因此切换到OkHttp仍是比较容易的。

         OkHttp具备以下优势:

1.      支持SPDY,共享同一个Socket来处理同一个服务器的全部请求;

2.      若是SPDY不可用,则经过链接池来减小请求延时;

3.      无缝的支持GZIP来减小数据流量;

4.      缓存网络数据,减小重复网络请求;

5.      支持HTTP2;

使用OkHttp既能够在工做线程中请求数据,也能够在UI线程中请求数据,这与Volley只能在工做线程中请求数据不一样。在工做线程中请求数据,数据返回后不须要从新开启线程解析数据,数据在请求线程中解析完后,直接抛到UI线程中进行展现。

3. 总结

在设计开发功能模块时,每每为了快速完成功能,忽略了模块的扩展性,当后续功能愈来愈复杂时,以前设计的功能、接口已经不能知足需求时,就要从新审视模块是否须要重构、优化,不能总在旧的代码上打补丁,形成代码难以阅读、维护。

4.   SPDY简介

SPDY是Google开发的基于传输控制协议(TCP)的应用层协议,用以最小化网络延迟,提高网络速度,优化用户的网络使用体验。SPDY并非一种用于替代HTTP的协议,而是对HTTP协议的加强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。SPDY协议在性能方面对HTTP作了很大的优化,语义方面并无作太大的修改。具体来讲是,SPDY使用了HTTP的方法和页眉,可是删除了一些报头并重写了HTTP中管理链接和数据转移格式的部分,基本上兼容HTTP。



网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区


相关文章:
【推荐】 上云、微服务化和DevOps,少走弯路的办法
【推荐】 非对称加密与证书(上篇)
【推荐】 django项目在uwsgi+nginx上部署遇到的坑

相关文章
相关标签/搜索