Android 进阶之性能优化 网络优化
我们对移动设备网络的需求无非快速,节省流量,节省电量。
一般而言:
快速可以通过缓存方式来实现;
节省流量可以通过缓存,压缩数据源等方式;
节省耗电量 可以通过批量操作,减少唤醒电源和电源持续时间来达到,本篇博文就是尝试从这几个方面对网络优化进行介绍:
网络缓存技术:
缓存网络数据
从网络上获取数据和从本地获取数据的速度差别是很大的,因此如果要提高获取数据的速度就必须尽量避免从网络上获取数据,对那些经常使用的网络数据要做好及时的缓存,以便加快访问的速度。
Android系统上HttpResponseCache是默认关闭的,这样会导致每次即使请求的数据内容是一样的也会需要重复被调用执行。我们可以通过下面的代码示例开启HttpResponseCache。
开启Http Response Cache之后,Http操作相关的返回数据就会缓存到文件系统上,不仅仅是自己编写的网络请求相关的数据会被缓存,另外引入的library库中的网络相关的请求数据也会被缓存到这个Cache中。
对于删除缓存数据可以有如下两种方式:
第一种方式是缓存溢出的时候删除最旧最老的文件
第二种方式是通过Http返回Header中的Cache-Control字段来进行控制的。如下图所示:
通常来说,HttpResponseCache会缓存所有的返回信息,包括实际的数据与Header的部分.一般情况下,这个Cache会自动根据协议返回Cache-Control的 内容与当前缓存的数据量来决定哪些数据应该继续保留,哪些数据应该删除。
但是在一些极端的情况下,或者是某些特殊的网络环境导致HttpResponseCache工作异常,在这些情况下就需要我们自己来实现Http的缓存Cache。一般不推荐自己重新实现自己的网络缓存方案,目前已经有不少著名的开源框架提供了完整的方案并获得无数项目的验证。这些方案包括Volly,okHTTP,Picasso等。
缓存UI数据。
对于UI界面上展现的是网络数据的情形我们可以使用文件系统,Preference,SQLite等数据存储方式将旧的数据存储起来,在下次加载的先现实给用户存储在本地的旧数据,而不是让用户看不到任何数据。
批量延迟传输与网络数据预取:
发起网络请求与接收返回数据都是比较耗电的,在网络硬件模块被激活之后,会继续保持几十秒的电量消耗,直到没有新的网络操作行为之后,才会进入休眠 状态,如果频繁发出网络请求会导致设备的无线蜂窝一直处于高消耗的状态为了避免这个问题我们可以通过预先判定那些是可能马上就会使用到的网络资源 ,或者将当前不是特别紧急的传输往后推辞,从而将多次零散的网络请求打包成一次操作,尽量避免频繁触发网络请求,提升设备的续航时间。
网络数据预取:
网络数据预取就是在还没使用之前缓存一部分数据,等到使用的时候直接使用缓存中的数据。
使用预取数据的难点在于如何判断事先获取的数据量到底是多少,如果预取的数据量偏少,那么就起不到什么效果,但是如果预取过多,又可能导致访问的时间过长。一个比较普适的规则是,在3G网络下可以预取1-5Mb的数据量,或者是按照提前预期后续1-2分钟的数据作为基线标准。在实际的操作当中,我们还需要考虑当前的网络速度来决定预取的数据量,例如在同样的时间下,4G网络可以获取到12张图片的数据,而2G 网络则只能拿到3张图片的数据。所以,我们还需要把当前的网络环境情况添加到设计预取数据量的策略当中去。判断当前设备的状态与网络情况。
延迟传输
最简单的延迟传输方法是通过将那些发出的网络请求,先暂存到一个PendingQueue里面,等到队列上的请求达到某个阈值的时候再触发Queue里面的网络请求。
根据当前网络状态调整网络策略:
在网络性能方面最直观的可能要算是网络延迟了,有时候我们会看到一个加载小图标一直打圈圈。会让用户觉得十分狂躁,为了解决这个问提可以通过为不同的网络状态设定不同的网络策略。
首先我们需要获取当前网络的情况:
通过上面的代码,我们可以获取到移动网络的详细子类型,例如4G(LTE),3G,如下图所示,获取到移动网络类型之后,我们可以根据当前网络的速率来调整网络请求的行为:
通常来说,我们可以把网络请求延迟划分为三档:例如把网络延迟小于60ms的划分为GOOD,大于 220ms的划分为BAD,介于两者之间的划分为OK。如果网络延迟属于GOOD的 范畴,我们就可以做更多比较激进的预取数据的操作,如果网络延迟属于BAD的范畴,我们就应该考虑把当下的网络请求操作Hold住等待网络状况恢复到 GOOD的状态再进行处理。
优化网络请求频率:
网络请求频率太低有可能会导致界面上无法呈现最新的数据,但是太频繁的网络请求又会导致CPU,内存,网络流量,电量等资源被持续消耗,所以在进行网络请求操作的时候一定要避免多度同步操作。
为了能够尽量的减少不必要的同步操作,我们需要遵守下面的一些规则:
- 首先需要对网络行为进行分类,区分需要立即更新数据的行为和其他可以进行延迟的更新行为,对不同的网络需求进行不同的处理。
例如,用户主动下拉刷新列表,这种行为需要立即触发网络请求,并等待数据返回。但是对于上传用户操作的数据,同步程序设置等等行为则属于可以延迟的行为 - 使用服务器推送来代替客户端对服务器的不断轮询同步。
- 在某些必须做同步的场景下,需要避免使用固定的间隔频率来进行更新操作,我们应该在返回的数据无更新的时候,使用双倍的间隔时间来进行下一次同步。
- 通过判断当前设备的状态来决定同步的频率,例如判断设备处于休眠,运动等不同的状态设计各自不同时间间隔的同步频率。
- 另外,我们还可以通过判断设备是否连接上WiFi,是否正在充电来决定更新的频率。我们甚至可以借助JobScheduler把请求的任务延迟到手机网络切换到WiFi,手机处于充电状态下再执行。
压缩传输数据:
为了能够减小网络传输的数据量,我们需要对传输的数据做压缩的处理,这样能够提高网络操作的性能。首先不同的网络环境,下载速度以及网络延迟是存在差异的,如下图所示:
通常来说,网络传输数据量的大小主要由两部分组成:图片与序列化的数据,那么我们需要做的就是减少这两部分的数据传输大小。
这部分在内存优化部分已经介绍过了,不同的图片格式在图片大小图片清晰度方面有较大的差异,在需要传输网络图片的时候需要选用适合的图片格式,下面是三种主流图片格式的对比。
对于JPEG与WEBP格式的图片,不同的清晰度对占用空间的大小也会产生很大的影响,适当的减少JPG Quality,可以大大的缩小图片占用的空间大小。
上述介绍的是从图片格式上选择图片资源,下面将从图片尺寸的选择上选择图片资源。
为了减小源图片的大小可以考虑为不同的使用场景提供当前场景下最合适的图片大小,例如针对全屏显示的情况我们会需要一张清晰度比较高的图片,而如果只是显示为缩略 图的形式,就只需要服务器提供一个相对清晰度低很多的图片即可。服务器应该支持到为不同的使用场景分别准备多套清晰度不一样的图片,以便在对应的场景下能 够获取到最适合自己的图片。
其次需要做的是减少序列化数据的大小。JSON与XML为了提高可读性,在文件中加入了大量的符号,空格等等字符,而这些字符对于程序来说是 没有任何意义的。我们应该使用Protocal Buffers,Nano-Proto-Buffers,FlatBuffer来减小序列化的数据的大小。
总而言之:
网络优化可以从如下几个方面入手:
1.从数据源方面优化可以通过压缩图片和序列化数据方式来降低电量和流量的损耗
2.从传输方式我们可以通过缓存数据,批量传输,调整网络请求频率等方式