目录
1.应用统计效果
2.介绍Android官方6.0之后推出的API网络太类 NetworkStatsManager:
3.统计查询方法(UID单个应用,所有应用)
4.统计过程中的发现的坑以及解决方案
5.统计结果与系统统计对比

1.应用统计效果

废话不多说,先上菜:

2.介绍Android官方6.0之后推出的API网络太类 NetworkStatsManager:
先看一下 android官方的 NetworkStatsManager API文档说明:

Android Developer NetworkStatsManager

NetworkStatsManager类 提供对网络使用历史和统计数据的访问,分为Summary queries(摘要查询)和 History queries(历史查询)

Summary queries(摘要查询)
这些查询汇总了整个时间间隔内的网络使用情况。因此,对于特定的密钥、状态、计量和漫游组合,只有一个桶。如果是用户范围和设备范围的摘要,则返回一个包含总网络使用情况的存储桶。

History queries(历史查询)
这些查询不会随时间聚合,但会聚合状态、计量和漫游。因此,一个特定的键可以有多个桶。

查询方法:

查询网络使用统计详情。结果过滤为仅包含属于呼叫用户的 uid(包含手机上每个应用的uid,统计所有应用总流量可用)queryDetails(int networkType, String subscriberId, long startTime, long endTime)查询指定 uid 的网络使用统计详细信息。(可查询单个应用流量)queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid)查询指定 uid 和标签的网络使用统计详细信息。queryDetailsForUidTag(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag)查询给定 uid、标签和状态的网络使用统计详细信息。仅可用于属于主叫用户的 uid。结果不会随时间聚合。queryDetailsForUidTagState(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag, int state)查询网络使用统计摘要。(查询多个应用流量统计)querySummary(int networkType, String subscriberId, long startTime, long endTime)查询网络使用统计摘要。结果是整个设备的汇总数据使用情况。结果是随着时间、状态、uid、标签、计量和漫游聚合的单个存储桶querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime)查询网络使用统计摘要。结果是属于调用用户的所有 uid 的汇总数据使用情况。结果是随着时间、状态和 uid 聚合的单个 Bucket。querySummaryForUser(int networkType, String subscriberId, long startTime, long endTime)

3.统计查询方法(UID单个应用,所有应用)

a. 需求:统计单个应用流量
可以从上面查询方法中选择 queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid)方法最符合需求,除了该方法之外还有querySummary()、queryDetails()也可以实现该需求。

queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid)

参数描述:

  • 1.networkType 查询网络类型 (ConnectivityManager.TYPE_WIFI,ConnectivityManager.TYPE_MOBILE)
    2.subscriberId 设备唯一id(android 10及以后设备 获取不了,可不传)
    3.startTime 查询指定时间段 开始时间戳
    4.endTime 查询指定时间段 结束时间
    5.uid 查询设备的Uid

    查询方法如下:

    queryDetailsForUid方法

 //统计工具类public static class Usage {long totalRxBytes;//总数据 下载字节long totalTxBytes;//总数据 上传字节long wifiTotalData;//wifi总流量数据long mobleTotalData;//移动总流量数据long mobleRxBytes;//移动 下载字节long mobleTxBytes;//移动 上传字节long wifiRxBytes;//wifi 下载字节long wifiTxBytes;//wifi 上传字节String uid;//包名}/*** 获取uid (单个)应用流量* @param context   上下文* @param startTime 开始时间* @param endTime   结束时间* @param uid       应用uid*/public static Usage getUsageBytesByUid(Context context, long startTime, long endTime, int uid) {Usage usage = new Usage();usage.totalRxBytes = 0;usage.totalTxBytes = 0;usage.mobleRxBytes = 0;usage.mobleTxBytes = 0;usage.wifiTxBytes = 0;usage.wifiTxBytes = 0;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {NetworkStatsManager nsm = (NetworkStatsManager) context.getSystemService(NETWORK_STATS_SERVICE);assert nsm != null;NetworkStats wifi = nsm.queryDetailsForUid(ConnectivityManager.TYPE_WIFI, null, startTime, endTime, uid);NetworkStats moble = nsm.queryDetailsForUid(ConnectivityManager.TYPE_MOBILE, null, startTime, endTime, uid);do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();wifi.getNextBucket(bucket);usage.wifiRxBytes += bucket.getRxBytes();usage.wifiTxBytes += bucket.getTxBytes();} while (wifi.hasNextBucket());do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();moble.getNextBucket(bucket);usage.mobleRxBytes += bucket.getRxBytes();usage.mobleTxBytes += bucket.getTxBytes();} while (moble.hasNextBucket());usage.wifiTotalData = usage.wifiRxBytes + usage.wifiTxBytes;usage.mobleTotalData = usage.mobleRxBytes + usage.mobleTxBytes;}return usage;}

querySummary方法查询统计

/*** 获取单个应用流量* @param context    上下文* @param startTime  开始时间* @param endTime    结束时间* @param uid        统计应用uid*/public static Usage getApplicationQuerySummary(Context context, long startTime, long endTime,int uid) {usage = new Usage();if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {NetworkStatsManager nsm = (NetworkStatsManager) context.getSystemService(NETWORK_STATS_SERVICE);assert nsm != null;try {NetworkStats wifi = nsm.querySummary(ConnectivityManager.TYPE_WIFI, null, startTime, endTime);NetworkStats mobile = nsm.querySummary(ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();wifi.getNextBucket(bucket);if(bucket.getUid() == uid){usage.wifiRxBytes += bucket.getRxBytes();usage.wifiTxBytes += bucket.getTxBytes();}} while (wifi.hasNextBucket());do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();mobile.getNextBucket(bucket);if(bucket.getUid() == uid) {usage.mobleRxBytes += bucket.getRxBytes();usage.mobleTxBytes += bucket.getTxBytes();}} while (mobile.hasNextBucket());usage.wifiTotalData = usage.wifiRxBytes + usage.wifiTxBytes;usage.mobleTotalData = usage.mobleRxBytes + usage.mobleTxBytes;} catch (RemoteException e) {e.printStackTrace();}}return usage;}

queryDetails 方法

 /*** 获取单个应用流量* @param context* @param startTime* @param endTime* @param uid*/public static Usage getApplicationQueryDetails(Context context, long startTime, long endTime,int uid) {usage = new Usage();if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {NetworkStatsManager nsm = (NetworkStatsManager) context.getSystemService(NETWORK_STATS_SERVICE);assert nsm != null;try {NetworkStats wifi = nsm.queryDetails(ConnectivityManager.TYPE_WIFI, null, startTime, endTime);NetworkStats mobile = nsm.queryDetails(ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();wifi.getNextBucket(bucket);if(bucket.getUid() == uid) {usage.wifiRxBytes += bucket.getRxBytes();usage.wifiTxBytes += bucket.getTxBytes();}} while (wifi.hasNextBucket());do {NetworkStats.Bucket bucket = new NetworkStats.Bucket();mobile.getNextBucket(bucket);if(bucket.getUid() == uid) {usage.mobleRxBytes += bucket.getRxBytes();usage.mobleTxBytes += bucket.getTxBytes();}} while (mobile.hasNextBucket());usage.wifiTotalData = usage.wifiRxBytes + usage.wifiTxBytes;usage.mobleTotalData = usage.mobleRxBytes + usage.mobleTxBytes;} catch (RemoteException e) {e.printStackTrace();}}return usage;}

b. 统计手机使用流量(所有应用)

可以从上面查询方法中可以看出 querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime, int uid)方法最符合需求,除了该方法之外还有querySummary()、queryDetails()querySummaryForUser()也可以实现该需求。

querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime)

参数描述:

  • 1.networkType 查询网络类型 (ConnectivityManager.TYPE_WIFI,ConnectivityManager.TYPE_MOBILE)
    2.subscriberId 设备唯一id(android 10及以后设备 获取不了,可不传)
    3.startTime 查询指定时间段 开始时间戳
    4.endTime 查询指定时间段 结束时间

querySummaryForUser 方法 统计

/*** 获取所有应用流量** @param context* @param startTime 开始时间* @param endTime   结束时间*/public static Usage getUsageByUidFromSummaryTotal(Context context, long startTime, long endTime) {usage = new Usage();if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {NetworkStatsManager nsm = (NetworkStatsManager) context.getSystemService(NETWORK_STATS_SERVICE);assert nsm != null;try{//querySummaryForUser   整个设备的汇总数据使用情况。NetworkStats.Bucket mobileBucket = nsm.querySummaryForUser(ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);usage.mobleTotalData = mobileBucket.getTxBytes() + mobileBucket.getRxBytes();usage.mobleTxBytes = mobileBucket.getTxBytes();usage.mobleRxBytes = mobileBucket.getRxBytes();NetworkStats.Bucket wifiBucket = nsm.querySummaryForUser(ConnectivityManager.TYPE_WIFI, "", startTime, endTime);usage.wifiTotalData = wifiBucket.getTxBytes() + wifiBucket.getRxBytes();usage.wifiTxBytes = wifiBucket.getTxBytes();usage.wifiRxBytes = wifiBucket.getRxBytes();}catch (Exception e){e.printStackTrace();}}return usage;}

此处就不每个方法都展开来写了,querySummary、queryDetails、querySummaryForUser几个方法也可以实现总流量统计,具体方法可以参考单个流量统计。

4.统计过程中的发现的坑以及解决方案

BUG1: 进行querySummaryForUser(int networkType, String subscriberId, long startTime, long endTime) 查询总流量分别为移动和wifi:

调用该方法时传入参数如下:
第一个参数: 移动类型 / wifi类型
第二个参数:传空字符串
第三个参数:今日零点零分的时间戳 如:2022-3-10:00:00:00(毫秒值)
第四个参数:获取当前系统时间戳 System.currentTimeMillis()

此方法指定查询某段时间的总流量使用情况,得到的结果是wifi正常,移动流量却是为0。这就觉得很纳闷了。

解决方法:

思路1:方法问题,先是参数不变替换成其它方法queryDetails、querySummary查询,结果依旧是0

思路2:参数问题,根据之前的结果既然wifi查询没有问题,那就排除时间参数三和四。剩下类型跟subscriberId(设备id)继续查看ConnectivityManager里面是否还有其它类型,以及TYPE_MOBILE类型参数说明,那也排除掉了。
subscriberId (设备id)android 10之后获取不了,其它第三方应用可以统计流量,没理由不行。没折,先去查看源码

在源码找到createTemplate方法里面525行,对subscriberId进行判断是否为null,然后上面传入参数字符串为空代入,不就是查询buildTemplateMobileAll方法嘛。最后subscriberId传入null值查询,结果数据有了。。

BUG2: 需求是查询今天抖音使用了多少流量,使用queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTim, int uide)方法调用两次 (移动和wifi)。

调用该方法时传入参数如下:
第一个参数:分别为 wifi和移动类型
第二个参数:null
第三个参数:今日零点零分的时间戳 如:2022-3-10:00:00:00(毫秒值)
第四个参数:获取当前系统时间戳 System.currentTimeMillis()
第五个参数:抖音的uid

返回结果居然是0,想了一下,好像今天还没打开过抖音。然后打开抖音 wifi和流量切换着刷了一会,然后在进行查询结果都是0

解决方法

思路1:替换方法,使用querySummary、queryDetails去查询,发现querySummary可以查询到即时流量,queryDetails还是查询结果为0。
思路2:换时间,是否是因为时间长度问题,把时间换成了昨天的就可以了。
在次尝试把结束时间拉长为次日,如:今天3月10号,第四个参数替换为:2022-3-11:00:00:00,结果也是可以正常测试出来。

总结:

bug1的坑刚开始着实没想到,subscriberId是String基础类型默认值一般都是空字符串,谁能想到需要传为值null。所以说还是应该多看源码,看看也不吃亏

bug2 的问题用得少,多试几次或者看下资料就知道了。queryDetails和queryDetailsForUid方法属于历史查询,该方法统计单位按小时统计,具体可以自行测试。而querySummary则是摘要查询,即在指定时间段内的流量(即时查询)。英文翻译成中文也不太友好啊

5.统计结果与系统统计对比

1.测试的手机有小米(Android 12)和vivo (Android 11)、魅族
小米系统自带原生统计基本一致,相差不超过1M
2.统计方法
这两种querySummary系列和queryDetails系列统计结果相差几十兆

下面是参考的几个博客地址:

https://blog.csdn.net/w7849516230/article/details/71705835
https://www.jianshu.com/p/52192441089b/

https://developer.android.com/reference/android/app/usage/NetworkStatsManager#queryDetails(int,%20java.lang.String,%20long,%20long)

应用统计效果Demo下载地址

android 统计应用流量 NetworkStatsManager相关推荐

  1. android 流量统计工具,Android 统计应用流量的使用情况

    Android 获取应用流量的使用情况有两种方法 TrafficStats NetworkStatsManager 是Android 6.0(API23)中新增加的类 这次我们使用的是第二种方法,记录 ...

  2. android取流量统计,Android 统计应用流量的使用情况

    Android 获取应用流量的使用情况有两种方法 TrafficStats NetworkStatsManager 是Android 6.0(API23)中新增加的类 这次我们使用的是第二种方法,记录 ...

  3. Android统计网络流量

    统计网络流量,可用ActivityManager或PackageManager获取各个应用的uid,然后再用TrafficStats获取.示例如下: private void printTraffic ...

  4. android统计app流量的软件,流量控(手机流量统计)app

    流量控(手机流量统计)app,为你带来准确,及时的流量通知,帮助用户时刻查询自己的手机流量和使用状况,管理程序的流量使用,全方面保证您的流量使用 流量控(手机流量统计)app介绍 流量控是一款统计安卓 ...

  5. Android 统计流量数据

    [流量统计] 使用到的类:TrafficStats(设备启动以来流量的统计信息) NetworkStatsManager(网络历史数据) 参考链接: (1)https://developer.andr ...

  6. android系统手机流量控制方法amp;,基于Android的手机流量控制软件全解.doc

    基于Android的手机流量控制软件全解 基于Android的手机流量控制软件 设计与实现 1 绪论 1.1 手机移动互联网进展 这些年,移动通信和互联网成为当今世界发展最快.市场潜力最大.前景最诱人 ...

  7. 基于c语言流量预警软件,基于Android的手机流量控制软件答案.doc

    基于Android的手机流量控制软件 设计与实现 1 绪论 1.1 手机移动互联网进展 这些年,移动通信和互联网成为当今世界发展最快.市场潜力最大.前景最诱人的两大业务.它们的增长速度都是任何预测家未 ...

  8. 求可以统计网络流量的VC代码,就象是金山网镖下面的那样

    求可以统计网络流量的VC代码,就象是金山网镖下面的那样..接收××K,发送××K,那种,会的千万帮忙阿....  现在作个东西,需要统计现在的网络流量.是累加的,在VC++中实现  希望高手帮忙,谢谢 ...

  9. 给网站添加代码统计-实现流量的变现

    前言 流量统计变现金,如果你有属于自己的网站,接入后,就可以变现 属于流量统计,不会添加任何广告,跟挂统计一样,还能赚钱,自己测试了一下,的确能赚钱 挂统计就给钱的平台,网站ip统计从原先的付费,到现 ...

最新文章

  1. 从零开始一起学习SLAM | 不推公式,如何真正理解对极约束?
  2. 在Windows Server 2008上部署SVN代码管理总结
  3. ajax 三种数据格式
  4. 双向TVS管 30KP42CA
  5. 算法系列教程04 - 算法相关的基础概念
  6. 构造函数 + 原型链继承 + 临摹面向对象模式的canvas动画框架
  7. sqoop从HDFS导出数据到Mysql,卡在Running job: job_1571036741208_0010不动了,或者map 100% reduce 0%不动了
  8. python 手动拼接json数据
  9. 如何保证http传输安全性
  10. c#动态编译并执行字符串
  11. linux 根目录read only,linux – 使readonly / etc可写
  12. 解决VMware虚拟机网络时长中断的问题
  13. 记录——《C Primer Plus (第五版)》第十章编程练习第十题
  14. 与数据库服务器通讯协议出错,与数据库服务器通讯异常
  15. RealMedia Analyzer(mp4修复软件)v0.30绿色版
  16. fastdb相关备忘
  17. 解析Linux商业应用现状
  18. csharp 在万年历中计算显示农历日子出错
  19. CentOS 6.X yum源更新(阿里云默认最新更新为CentOS6.10)
  20. APP渗透—Android 7.0 抓包(教程)

热门文章

  1. 【狂神说Java笔记】Java基础
  2. win10服务器文件夹显示不全,win7、win10部分软件窗口显示不完整解决办法
  3. python十六进制转十进制
  4. 两化融合试点资料申报指南(附视频教程以及案例模板)
  5. 疯狂的蚂蚁----ant
  6. 文字识别,语音输入全场景应用解析,让你的职场办公效率狂飙
  7. 万维网运行原理分析实验
  8. 6.5 万维网www与HTTP协议
  9. OSI参考模型层次结构
  10. ac1900 linksys 恢复_Linksys-AC1900路由器 - 刷机指南