最近逛github,突然发现facebook居然写了个检测网络质量的框架源码地址,好奇心驱使那就研究一下吧。分析源码之前,先看一看官方给我们提供的例子效果:

这个是faceBook官方为这个小框架提供的demo,点击Test按钮即可测出当前手机网络速度的质量,但是这里出现了一串英文EXCELLENT,什么鬼这表示的速度是什么,查询源码找到包含参数的这个枚举类

public enum ConnectionQuality {/*** Bandwidth under 150 kbps.*/POOR,/*** Bandwidth between 150 and 550 kbps.*/MODERATE,/*** Bandwidth between 550 and 2000 kbps.*/GOOD,/*** EXCELLENT - Bandwidth over 2000 kbps.*/EXCELLENT,/*** Placeholder for unknown bandwidth. This is the initial value and will stay at this value* if a bandwidth cannot be accurately found.*/UNKNOWN
}

英文已经说明的很清楚了,测试的当前网络速度2000 kbps以上,说明手机当前网络质量不错吆!好,看完例子,接下来进入重点

mConnectionClassManager = ConnectionClassManager.getInstance();mDeviceBandwidthSampler = DeviceBandwidthSampler.getInstance();.....mListener = new ConnectionChangedListener();
 @Overrideprotected void onPause() {super.onPause();mConnectionClassManager.remove(mListener);}@Overrideprotected void onResume() {super.onResume();mConnectionClassManager.register(mListener);}

例子当中与框架交互的首先映入眼帘的就是这几句代码,可以看到,小框架中声明了两个单例ConnectionClassManager类和DeviceBandwidthSampler类,然后通过ConnectionClassManager注册了一个监听回调方法,用于显示网络变化,既然是一直在监听网络速度变化的,那么八成会有死循环一直运行监测网速。ok,先看看DeviceBandwidthSampler类,验证一下推论。

 private DeviceBandwidthSampler(ConnectionClassManager connectionClassManager) {mConnectionClassManager = connectionClassManager;mSamplingCounter = new AtomicInteger();mThread = new HandlerThread("ParseThread");mThread.start();mHandler = new SamplingHandler(mThread.getLooper());}

这个类的构造方法声明了一个HandlerThread,看到 HandlerThread,已经能看出来,它是想在在线程当中执行消息队列,start()方法创建一个新的消息队列管理,类Loop,然后进行轮询查看是否有消息,有消息就处理,接下来创建一个绑定这个 HandlerThread的Loop的Handler,用来发消息。按照猜测接下来就是利用Handler来循环传送消息了,在点击按钮下载图片的时候调用了 mDeviceBandwidthSampler.startSampling()方法发送了消息。

 /*** 开始检测网络速度*/public void startSampling() {if (mSamplingCounter.getAndIncrement() == 0) {//看这里mHandler.startSamplingThread();mLastTimeReading = SystemClock.elapsedRealtime();}}
      public void startSamplingThread() {sendEmptyMessage(SamplingHandler.MSG_START);}

看这个方法链的调用,最终通过发消息的方式实现循环

 public void handleMessage(Message msg) {switch (msg.what) {case MSG_START:addSample();sendEmptyMessageDelayed(MSG_START, SAMPLE_TIME);

消息处理中每隔一段时间重新发送相通消息,那么计算处理网络速度的也只有 addSample方法了

 protected void addSample() {//得到手机自启动以来的总共消耗的流量long newBytes = TrafficStats.getTotalRxBytes();long byteDiff = newBytes - sPreviousBytes;//有变化的时候才去计算if (sPreviousBytes >= 0) {synchronized (this) {//得到当前的时间long curTimeReading = SystemClock.elapsedRealtime();//传入流量变化的差值和时间差值mConnectionClassManager.addBandwidth(byteDiff, curTimeReading - mLastTimeReading);mLastTimeReading = curTimeReading;}}sPreviousBytes = newBytes;}

这个方法首先获得了手机自启动以来的流量消耗的总量,然后用当前量减去上一次的量,也就是说网络速度是通过单位时间内流量的差值进行计算的,接下来进入 mConnectionClassManager.addBandwidth进行计算

public synchronized void addBandwidth(long bytes, long timeInMs) {// Ignore garbage values.// 变化量小于10计算终止重新记录值if (timeInMs == 0|| (bytes) * 1.0 / (timeInMs) * BYTES_TO_BITS < BANDWIDTH_LOWER_BOUND) {return;}double bandwidth = (bytes) * 1.0 / (timeInMs) * BYTES_TO_BITS;mDownloadBandwidth.addMeasurement(bandwidth);// 如果它为true连续mSampleCounter+1if (mInitiateStateChange) {mSampleCounter += 1;// 判断当前的值和期望的值是否处在同一个范围内,不处在同一个范围内,连续5次计算的值和波动值在同一个范围内的话,减少网络波动造成的误差if (getCurrentBandwidthQuality() != mNextBandwidthConnectionQuality.get()) {// 计数重新开始,mInitiateStateChangemInitiateStateChange = false;mSampleCounter = 1;}/*** 网络稳定到5次以上才通知计算结果,波动比较大的时候不通知,优化更准确*/if (mSampleCounter >= DEFAULT_SAMPLES_TO_QUALITY_CHANGE&& significantlyOutsideCurrentBand()) {mInitiateStateChange = false;mSampleCounter = 1;// 确定改变的时候设置通知mCurrentBandwidthConnectionQuality.set(mNextBandwidthConnectionQuality.get());notifyListeners();}return;}// 如果上一个速率和现在的计算速率不一样,那么mInitiateStateChange=true,mNextBandwidthConnectionQuality储存当前的速录if (mCurrentBandwidthConnectionQuality.get() != getCurrentBandwidthQuality()) {mInitiateStateChange = true;mNextBandwidthConnectionQuality = new AtomicReference<ConnectionQuality>(getCurrentBandwidthQuality());}}

计算的核心都在这个方法里面,首先判断如果前后消耗流量的变化小于10kbs那么,重新记录值计算终止,满足条件通过mDownloadBandwidth.addMeasurement方法计算出变化的平均值,也就是通过指数移动平均值来重新估算这个差值,由于移动网络的不稳定性,通过计算平均值计算会更准确,假设当前网络已经有了上一次的速度,但是由于某种原因,速度发生变化,比如信号不好,那么此时为了排除误差,采取连续计算五次方式,也就是说如果当前网络速度变化值满足五次在同一个范围内并且和上一次计算的速度不在同一范围内的话,那么通知客户端速度改变,当前速度值刷新,也就是网络速度值必须保持5次计算都在同一个范围内,才认为当前网络质量的速度为准确的,也就是说假设当前速度为100kbs,信号突然不好掉到30kbs,但是有可能信号又突然恢复了,那么当前速度还是100kbs,没必要通知客户端网络速度发生了改变。这种方式可以是测量值更接近真实情况的值,当然不肯能100%准确。

最后看一下指数移动平均值是怎么计算的

public void addMeasurement(double measurement) {// 0.95double keepConstant = 1 - mDecayConstant;// 累加次数大于20次if (mCount > mCutover) {// 自然对数Math.log(mValue),Math.exp() 函数返回 exmValue = Math.exp(keepConstant * Math.log(mValue) + mDecayConstant* Math.log(measurement));}// 0<mCount<20走这里else if (mCount > 0) {// 如果mCount是4的话double retained = keepConstant * mCount / (mCount + 1.0);double newcomer = 1.0 - retained;mValue = Math.exp(retained * Math.log(mValue) + newcomer* Math.log(measurement));}// 第一次mCount是等于0的else {mValue = measurement;}mCount++;}

指数平均值通过前后变化的两个数进行权重平均值计算,至于这样计算为什么准确,笔者暂时有点懵逼,但是这个算法是统计学当中的,不管怎么说阅读此代码让笔者了解到,想成为高手中的战斗机算法必须牛,那么接下来的目标就是拾起曾经遗忘的数学

facebook的network-connection-class(测量移动端网络质量)源码详解相关推荐

  1. php io select,Python IO多路复用之——select方案服务端和客户端代码【python源码详解】...

    准备文件: IO.py  服务端代码 tcp_c.py 客户端代码 IO.py 代码: from select import * #引入 select 模块 from socket import * ...

  2. Web端即时通讯技术原理详解

    Web端即时通讯技术原理详解 前言 在web端的IM即时通讯应用,由于浏览器的兼容性以及其固有的"客户端请求服务器处理并响应"的C/S通信模型,造成了要在浏览器中实现一个兼容性较好 ...

  3. WCF服务端运行时架构体系详解[下篇]

    作为WCF中一个核心概念,终结点在不同的语境中实际上指代不同的对象.站在服务描述的角度,我们所说的终结点实际上是指ServiceEndpoint对象.如果站在WCF服务端运行时框架来说,终结点实际上指 ...

  4. ios无痕埋点_移动端无痕埋点实践详解(二)

    0x01 前言 在移动端无痕埋点实践详解(一)这篇文章大致总结了移动端无痕埋点的基本原理.主要介绍了什么是无痕埋点,无痕埋点的基础数据流程以及在Android系统上总体思路.这篇文章着重总结下无痕埋点 ...

  5. python 录制web视频_Python django框架 web端视频加密的实例详解

    视频加密流程图: 后端获取保利威的视频播放授权token,提供接口api给前端 参考文档:http://dev.polyv.net/2019/videoproduct/v-api/v-api-play ...

  6. nodejs框架微商个人相册多端小程序源码

    介绍: 微商个人相册多端小程序源码,用于个人相册展示,适合微商,有客服联系,无需后台管理系统,小程序上直接进行管理,没有登录账号只拥有查看功能. 功能介绍: 1.首页进行相册展示,采用分页 2.列表页 ...

  7. Nodejs框架+uniapp前端微商个人相册多端小程序源码

    简介: 微商个人相册多端小程序源码,用于个人相册展示, 适合微商,有客服联系,无需后台管理系统, 小程序上直接进行管理,没有登录账号只拥有查看功能. 网盘下载地址: http://kekewl.cc/ ...

  8. 梦幻诛仙linux纯端架设教程,梦幻诛仙 一键端搭建iOS安卓双端+完整后台源码+各种工具附带视频架设教程...

    游戏说明: 梦幻诛仙一键端搭建iOS安卓双端+完整后台源码+各种工具,视频架设教程 在游戏内当前聊天窗口输入  dmmhzxnb ,开启后台.  提示GM后台已开启. 在左上角Press Enter ...

  9. 微商个人相册多端小程序源码

    简介: 微商个人相册多端小程序源码 程序介绍 1.首页进行相册展示,采用分 2.列表页面以文字形式进行分类,管理员可进行添加,修改和排序 网盘下载地址: http://kekewl.org/RgBOf ...

  10. niushop多商户商户端手机uniapp源码v4单商户v4_Saas开源版含uniapp以及niushop社区团购标准版源码开源的区别

    推荐指数五颗星:Niushop商城社区团购系统源码支持uniapp源码一键生成小程序,H5,APP 1.niushop多商户V4 包含标准版,企业版,分销版,旗舰版,城市版 其中城市版为全模块版 内含 ...

最新文章

  1. 《深入理解计算机系统》第七章——链接知识点总结
  2. 希尔排序(插入排序的优化算法)
  3. int 范围_Java学习之随机生成5个(范围1——33)不同数字的思考
  4. 理解go func背后发生了什么?
  5. 高通处理器命名中文化
  6. WGS84坐标系、Web墨卡托、GCJ02坐标系、BD09坐标系—常用坐标系简述
  7. iptables、firewalld和ufw区别linux
  8. 2020农行研发中心面经
  9. 路由器与交换机的区别与联系
  10. 从项目中由浅入深的学习vue,react,微信小程序和快应用(1)
  11. kiv8测量方法_measure_测量 | measure_Scikit image_参考手册_非常教程
  12. photoshop合并图层:向下合并、合并选中层、合并可见图层、拼合图像操作
  13. java csrf 跨域_Django跨域请求CSRF的实例方法
  14. JavaScript中事件的绑定与解绑
  15. Promise及其应用
  16. 深入理解Java虚拟机(四)Eden、Survivor、老年代、GC日志
  17. dropout keep_prob参数
  18. Python教你每把轻松吃鸡
  19. Outstanding Teams Award
  20. 机器人控制——PID参数整定

热门文章

  1. 计算机无法启动怎么重装系统,电脑无法启动系统怎么重装
  2. 联想k50+开发者模式+linux,联想 K50-T5中文Recovery刷机教程
  3. 关于如何利用学生邮箱申请jetbrains免费全家桶
  4. vs无法启动程序系统找不到指定文件
  5. springboot用jar方式调试,用war方式部署到tomcat
  6. 未来,将是Captain technology新能源汽车的舞台
  7. 最详细windows xp下安装mac的教程(转自远景论坛69nc)
  8. 三日济州岛,何以韩国人眼光?-让自己慢下来(43)
  9. word中怎样输入 包含 真包含 不等于 等集合符号
  10. html表格内容自动换行符,html表格内容自动换行