目录
- 一、TrafficStats类简介
- 二、demo示例
一、TrafficStats类简介
TrafficStats
Android API 8提供了android.net.TrafficStats类。
通过此类能获取设备重启以来网络信息,部分函数如下所示:
static long getMobileRxBytes() //获取通过移动数据网络收到的字节总数
static long getMobileTxBytes() //通过移动数据网发送的总字节数
static long getTotalRxBytes() //获取设备总的接收字节数
static long getTotalTxBytes() //获取设备总的发送字节数
static long getUidRxBytes(int uid) //获取指定uid的接收字节数
static long getUidTxBytes(int uid) //获取指定uid的发送字节数
通过文档及上述函数可以知道,TrafficStats能够获取设备的数据流量和总的网络流量消耗(一般情况下也就得到Wi-Fi下的流量信息);可以查询uid对应的流量信息,而uid可以通过应用的包名查询到,因此能够查询某个应用的流量统计信息(不考虑shareuid)。非常方便的是,它的使用不需要特别的权限。另一方面它也一些限制:
(1)无法获取应用的数据流量消耗
从文档中仅能获取到指定uid的流量,但无法区分不同网络类型下的消耗
间接方法是通过监听网络切换,做好流量记录(但是要保证你的应用一直存活,且一定准确接收到网络切换信息),基本不可用。
(2)无法获取某个时间段内的流量消耗
从API文档中看,函数参数没有与时间相关的信息。而且重要的一点是,TrafficStats类中记录的是设备重启以来的流量统计信息。因为TrafficStats 类,底层还是读取/proc/net/xt_qtaguid/stats 对内容进行解析,将得到对应的结果返回上层。
链接:
Android应用流量统计——NetworkStatsManager使用
二、demo示例
本地使用demo验证流量消耗情况:获取一段时间内哪些应用进行了网络访问以及具体的流量消耗情况
package com.android.networktest;import android.app.AppOpsManager;
import android.app.usage.NetworkStats;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);hasPermissionToReadNetworkStats();test();}private boolean hasPermissionToReadNetworkStats() {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return true;}final AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,android.os.Process.myUid(), getPackageName());if (mode == AppOpsManager.MODE_ALLOWED) {return true;}requestReadNetworkStats();return false;}// 打开“有权查看使用情况的应用”页面private void requestReadNetworkStats() {Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);startActivity(intent);}public void test() {NetworkStatsManager networkStatsManager = (NetworkStatsManager) getSystemService(Context.NETWORK_STATS_SERVICE);long startTime = System.currentTimeMillis() - 1000 * 60 * 1000; // 从过去60x1000秒开始计算long endTime = System.currentTimeMillis();NetworkStats networkStats = null;NetworkStats.Bucket bucket = new NetworkStats.Bucket();try {networkStats = networkStatsManager.querySummary(ConnectivityManager.TYPE_WIFI,"",startTime,endTime);} catch (RemoteException e) {throw new RuntimeException(e);}networkStats.getNextBucket(bucket); // 获取第一个Bucketdo {// 获取应用程序UIDint uid = bucket.getUid();// 获取应用程序名称String packageName = getPackageManager().getNameForUid(uid);// 获取应用程序消耗的数据量long rxBytes = bucket.getRxBytes();long txBytes = bucket.getTxBytes();Log.d("henry------NetworkStats", "App: " + packageName + " uid : " + uid +" RX bytes: " + rxBytes + ", TX bytes: " + txBytes);} while (networkStats.getNextBucket(bucket)); // 获取下一个Bucket,直到没有更多Bucket为止}
}
Manifest权限添加一下:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions"/>
LOG打印如下:
可以看到对应uid 所消耗的流量情况
但是uid为1000 即系统权限的应用有很多,无法进一步区分哪些系统应用默认进行了网络访问。
NetworkStatsManager底层调用的是如下节点的数据:可以看多最多细分只能划分到uid。
总结:
NetworkStatsManager主要用来获取三方应用用户自行下载的app流量所消耗的情况,对于系统权限uid,uid相同但非同一个应用的app或服务无法进一步区分。