在当前WiFi普及的大环境下,我们很容易忽略网络的问题,特别是在我们在室内测试的时候。
基于下面三个原因,我们有必要做网络优化
有效地网络使用能够提高用户体验。
有效使用网络能够大幅减少电量使用,因网络传输数据是电量消耗的一个最重要的来源。
有效的网络使用有时候能够显著减少占用带宽。
简单的优化
访问网络之前,先检测网络是否可用
- 通过ConnectivityMananger来判断
- 通过Broadcast Receiver监听网路变化。
下载优化
1.优化下载机制
Radio State Machine.
上图是使用AT&T的3G信号的计时情况,资料来自于efficient-network-access
Full power: 当网络连接激活时,设备可以以最大可能的速率传输数据
Low Power:Full power的使用50%电量的点状态。
Standby:最小的能量状态,当没有网络使用申请或者网络被激活。
因为APP每次创建一个网络connections,从连接到关闭会经历上图中的Radio State Machine.下图是对比不绑定数据传输和绑定数据传输的使用情况:
绑定数据传输会让Radio大多数时候处于standby。
在这个设计原则的指引下,我们应该尽可能做到,预先获取需要的数据,尽可能把需要的数据绑定传输给APP端,重用网络连接(把多个HTPP GET请求压缩到一个HTPP GET请求)。下面举几个例子
音乐播放器,在播放音乐的同时,通过突发传输流的方式保持一首歌的缓冲,而不是一次性下载整个专辑,这样会让网络连接一直保持在激活状态。
新闻阅读器,在不影响APP体验的前提下,预先下载用户可能需要用到的新闻列表(至少是推荐列表)的标题,内容,缩略图,大图应该在用户点击缩略图的时候再去下载。
视频,每隔2-5分钟预先缓冲接下来几分钟用户要看到的视频帧。
下面是可以帮助实现批量处理网络使用的工具
2.优化数据更新请求,这里的更新包括数据更新和版本更新,通过下面几点做到
- 没有网络的时候,停止后台的更新请求
- 当电量低的时候,减少更新频率
- 用推送代替轮询,来查询服务器是否有新数据。
- 如果要使用轮询,可以使用 JobScheduler, AlarmManager, and Firebase JobDispatcher
3.优化冗余的下载,通过下面几点做到。
通过RESTfull API的设计原则,尽量做到API只传输需要的数据。最常见的例子就是,列表和详情,列表API应该仅仅包括当前显示要的数据,详情API应该是另外一个包含更多信息的。不合理的设计中,列表API会包含详情API。
服务端应该提供,根据所需尺寸获取对应大小的图片,七牛已经帮我们实现了。使用WebP格式;同样的照片,采用WebP格式可大幅节省流量,相对于JPG格式的图片,流量能节省将近 25% 到 35 %;相对于 PNG 格式的图片,流量可以节省将近80%。最重要的是使用WebP之后图片质量也没有改变
缓存经常使用的数据,前提是必须保证这个数据是最新的,可以通过如下代码实现
// url represents the website containing the content to place into the cache.
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
long currentTime = System.currentTimeMillis();
long expires = conn.getHeaderFieldDate("Expires", currentTime);
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);
// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
// Skip update
} else {
// Parse update
lastUpdateTime = lastModified;
}
- 用增量升级代替全量升级,参考bugly的补丁升级
备注:敏感的数据可以存储到app安装目录,非敏感数据可以存储到sdcard,但是需要注意的是,如果存储到APP安装目录,有可能会因为手机内存紧张,而被某些工具清除掉。
4.根据网络连接类型来修改相应的下载策略
这个原则,就是在网络最好的情况下载最大的数据,下面代码可以帮助我们理解
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
TelephonyManager tm =
(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
int PrefetchCacheSize = DEFAULT_PREFETCH_CACHE;
switch (activeNetwork.getType()) {
case (ConnectivityManager.TYPE_WIFI):
PrefetchCacheSize = MAX_PREFETCH_CACHE; break;
case (ConnectivityManager.TYPE_MOBILE): {
switch (tm.getNetworkType()) {
case (TelephonyManager.NETWORK_TYPE_LTE |
TelephonyManager.NETWORK_TYPE_HSPAP):
PrefetchCacheSize *= 4;
break;
case (TelephonyManager.NETWORK_TYPE_EDGE |
TelephonyManager.NETWORK_TYPE_GPRS):
PrefetchCacheSize /= 2;
break;
default: break;
}
break;
}
default: break;
}
5.使用网络缓存
对服务端返回数据进行缓存,设定有效时间,有效时间之内不走网络请求,减少流量消耗。对网络的缓存可以参见HttpResponseCache
6.断点下载和上传
断点续传,文件、图片等的下载,采用断点续传/下载,不浪费用户之前消耗过的流量。最典型的例子就是断点下载升级版本。
优化数据传输格式
重构数据传输
- 可以通过把请求数据zip压缩的方式传输。
- 使用Protocol Buffers or FlatBuffers 替代gson, xml,因为前两者更加简洁,轻量级。
优化上传
大文件上传,包括图片,视频等
大文件上传失败率比较高,,同时带宽、时延、稳定性等因素在此场景下的影响也更加明显;
避免整文件传输,采用分片传输;根据网络类型以及传输过程中的变化动态的修改分片大小;每个分片失败重传的机会。
使用好工具
参考文档:
https://developer.android.com/training/efficient-downloads/efficient-network-access.html
https://developer.android.com/topic/performance/power/network/action-any-traffic.html
https://developer.android.com/reference/android/net/http/HttpResponseCache.html