TrafficStats Api是安卓系统中的一个API,用于计算每日数据使用量。

10

对于 Android 中 TrafficStats 的以下两种方法存在疑惑: getUidTxBytes(int uid) 与 getUidRxBytes(int uid), 这两个方法返回该 UID 通过网络传输和接收的字节数。但是它的时间单位是什么?是每秒钟吗? 如果我想计算每个应用程序每天传输和接收的数据量,我该怎么办?我考虑了一种方法,将数据存储在 SQL 中并不断向表中添加数据。这样做合适吗?


你尝试过记录一些日志,看看计数器何时被重置了吗?我会假设计数器在进程创建时开始,并在进程完成时重置(即手机关闭时)。 - Kurtis Nusbaum
谢谢您的回答。手机关机后计数器被归零。现在,我将继续下一步,根据正常运行时间计算数据使用量。 - Naba
4个回答

6
这些计数器包含自上次重启以来的字节计数。在某些手机上,这些计数器可能会定期重置,但大多数情况下,它们只会在重新启动后重置。进入飞行模式或在移动网络和Wi-Fi之间切换不会重置这些计数器。
一个重要的点是,这些计数器不包括数据包开销,只包括有效负载大小。因此,通常意味着3-4%的数据可能无法解释。然而,如果是流媒体、种子或VoIP应用程序,其中数据包有效负载很小,那么未解释的数据量可能会更高。
有趣的是,getTotalRxBytes(所有接口接收的字节数,例如移动和Wi-Fi组合)和getMobileRxBytes(仅在移动接口上接收的字节数)都包括所有开销。因此,你的应用程序字节计数总数将少于你的接口字节计数总数,因此也少于你的网络运营商向你收费的数据量。
最后一个要点是,大多数流媒体应用程序不会在其自己的UID下记录其数据。它们记录在system.media UID下。因此,如果你正在监视YouTube的数据使用情况,实际上只有很少一部分数据会出现在该应用程序下;其余的数据将在media UID(1013)下。

这个答案是否正确?请看这里。 - Mateen Ulhaq
我的回答已经超过6年了,当时是正确的。函数之间的数据包头差异可能已经得到纠正。我的建议是让您的应用程序下载一个已知文件大小并验证UID API返回的字节数是否大于文件大小,这将验证现在是否包括数据包头大小。请记住,不同操作系统版本的行为可能会有所不同,并且文档记录的行为与实际行为可能会有所不同。 - OldSchool4664

6
这些是“自接口启动”或“自具有此UID的应用程序启动”以来的计数器。因此,如果您的手机进入“飞行模式”,然后返回,计数器可能会重新从零开始。如果您需要每秒值,则需要每秒调用这些函数,然后使用与上次调用的差值。如果差值为负数,只需使用该值即可,这意味着计数器从零重新开始。

还有一件事:据我所知,这些计数器仅计算TCP/IP。不包括UDP。因此,如果您需要非常精确的计算,并且所涉及的应用程序使用UDP/IP或除TCP之外的任何其他协议,则这些计数器将是错误的。

有关此功能如何工作的见解,请查看免费提供的Android源代码。有关文件是./frameworks/base/core/jni/android_net_TrafficStats.cpp

此函数从/proc/uid_stat/[uid]/tcp_snd获取数据。如果您需要更多信息,请深入了解Linux内核...


总网络接口和仅移动网络接口之间有什么区别。getMobileRxBytes返回的值非常低,而getTotalRxBytes返回合理的值。 - Naba
getMobileRxBytes 返回通过3G/4G/GPRS等接收的数据。 getTotalRxBytes 包括所有接收的数据,包括通过 Wi-Fi 接收的。 - haimg
如何重置Traffic Stats Api的计数器?是否有任何系统调用可供使用?实际上,每次设备重新启动,它都会删除早期的文件并创建新文件,从而在每次重新启动时设置新的计数器。我能否从我的应用程序中以编程方式执行此操作? - Naba
谢谢。我根据将当前值减去上次存储的值的方法使其在单击重置时正常工作。 - Naba
嗨Haimg,当我播放YouTube时,设备接收的总字节数,即getTotalRxBytes,增加了近5 MB,但从getUidRxBytes(int uid)接收的字节数(其中uid是YouTube用户ID)却很少。我做错了什么吗? - Naba
1
针对当前的 API 版本(20/21),TrafficStats 似乎计算 TCP 和 UDP 的流量统计信息。参考链接 - Janus Varmarken

2

在这里,我获取那些具有互联网权限的应用程序,您可以更改权限名称并根据需要获取应用程序。

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";

}

你确定吗?它会给我所有Android操作系统的数据统计吗? - Milan Gajera
当然可以。已经在 https://play.google.com/store/apps/details?id=com.jsk.datausagemonitor&hl=en 实现了。 - Narendra Sorathiya
当我遇到API级别23时,它没有向我提供任何MB或字节。 - Milan Gajera
当我在Nougat和KitKat中安装了您建议的应用程序时,我没有得到任何数据。应用程序显示“没有可用的应用程序!”。你可以帮助我吗? - Milan Gajera
为什么您给了一星评价? - Narendra Sorathiya

0

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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接