对Android的以下两个TrafficStats的方法有混淆: getUidTxBytes(int uid)和getUidRxBytes(int uid),这两个方法返回这个UID通过网络传输和接收的字节数。但是它的时间单位是什么,是每秒吗?如果我想计算每个应用每天发送和接收的数据,我应该怎么做。我想了一种方法,将数据存储在 sql 中并继续向表中添加数据。这是正确的方法吗?
4 回答
这些是“自从接口启动以来”或“自从具有此 UID 的应用程序启动以来”的计数器。因此,假设您的手机进入“飞行模式”然后返回,计数器可能会再次从零开始。如果您需要每秒值,则需要每秒调用这些函数,然后使用上次调用的增量。如果 delta 为负,则直接使用该值,这意味着计数器再次从零开始。
还有一件事:据我所知,这些计数器只计算 TCP/IP。不是UDP。因此,如果您需要非常精确的记帐,并且相关应用程序使用 UDP/IP 或除 TCP 之外的任何其他协议,则这些计数器将是错误的。
要了解此功能的工作原理,请查看免费提供的 Android 源代码。有问题的文件是./frameworks/base/core/jni/android_net_TrafficStats.cpp
该函数从 中获取数据/proc/uid_stat/[uid]/tcp_snd
。如果您需要有关此的更多信息,则需要深入研究 Linux 内核......
这些计数器包含自上次重新启动以来的字节数。一些电话这些计数器可能会定期重置,但大多数时候它们只会在重新启动后重置。进入飞行模式或在移动和 Wi-Fi 之间切换不会重置这些计数器。
重要的一点是这些计数器不包括数据包开销,只包括有效负载大小。所以通常这意味着 3-4% 的数据可能下落不明。但是,如果它是数据包有效负载较小的流式传输、洪流或 VoIP 应用程序,则可能会有更多的数据未计入。
有趣的是,getTotalRxBytes(在所有接口上接收到的字节,前移动设备和 Wi-Fi 相结合)和 getMobileRxBytes(仅在移动接口上接收到的字节)包括所有字节,包括开销。因此,基本上,您的应用程序字节总数将少于您的接口字节总数,因此少于您的网络运营商向您收费的数据量。
最后一点,大多数流媒体应用程序不会在自己的 UID 下考虑他们的数据。它们在 system.media UID 下计算。因此,如果您正在监控 YouTube 的数据使用情况,那么该应用程序下实际上只会显示非常少量的数据;其余的将在媒体 UID (1013) 下。
在这里,我获取了那些具有 Internet 权限的应用程序,您可以更改权限名称并根据需要获取应用程序。
ArrayList<AppObject> listApps;
public void getAllAppList() {
listApps = new ArrayList<AppObject>();
PackageManager p = getPackageManager();
List<ApplicationInfo> packages = p.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo applicationInfo : packages) {
try {
PackageInfo packageInfo = p.getPackageInfo(applicationInfo.packageName, PackageManager.GET_PERMISSIONS);
String[] permissions = packageInfo.requestedPermissions;
for (String permissionName : permissions) {
if (permissionName.equals("android.permission.INTERNET")) {
ApplicationInfo appInfo = packageInfo.applicationInfo;
AppObject appObject = new AppObject();
appObject.appDrawable = getPackageManager().getApplicationIcon(appInfo);
appObject.appName = (String) getPackageManager().getApplicationLabel(appInfo);
appObject.dataUsage = getDataUsage(appInfo);
listApps.add(appObject);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
Debug.e("APP_SIZE", ":" + listApps.size());
appsAdapter.addAll(listApps);
}
public String getDataUsage(ApplicationInfo appInfo) {
int uid = appInfo.uid;
double received = (double) TrafficStats.getUidRxBytes(uid) / (1024 * 1024);
double sent = (double) TrafficStats.getUidTxBytes(uid) / (1024 * 1024);
double total = received + sent;
return String.format("%.2f", total) + " MB";
}
getUidRxBytes() 和 getUidTxBytes() 基本上分别用于接收和发送的字节。要监控每个应用程序的数据,只需找到每个进程的 uid 并找到每个进程的相应数据,这将是每个应用程序的数据,然后您可以使用此代码进行计算。
TextView totData = (TextView)findViewById(R.id.totData);
TextView wifiTot = (TextView)findViewById(R.id.wifitotData);
TextView wifiTX = (TextView)findViewById(R.id.wifiUpData);
TextView wifiRX = (TextView)findViewById(R.id.wifiDownData);
TextView mobileTot = (TextView)findViewById(R.id.mobtotData);
TextView mobTX = (TextView)findViewById(R.id.mobUpData);
TextView mobRX = (TextView)findViewById(R.id.mobDownData);
/*
* Converting bytes to MB
*/
long rxBytes = TrafficStats.getTotalRxBytes()/1048576;
long txBytes = TrafficStats.getTotalTxBytes()/1048576;
long mobUpload = TrafficStats.getMobileTxBytes()/1048576;
long mobDown = TrafficStats.getMobileRxBytes()/1048576;
long wifiUpload = txBytes-(mobUpload);
long wifiDown = rxBytes-(mobDown);
wifiRX.setText(Long.toString(wifiDown));
wifiTX.setText(Long.toString(wifiUpload));
long wifitot = wifiUpload+wifiDown;
wifiTot.setText(Long.toString(wifitot));
mobTX.setText(Long.toString(mobUpload));
mobRX.setText(Long.toString(mobDown));
long mobTot = mobUpload+mobDown;
mobileTot.setText(Long.toString(mobTot));
totData.setText(Long.toString(wifitot+mobTot));