目录
- 一、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 {
@Override
protected 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); // 获取第一个Bucket
do {
// 获取应用程序UID
int 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或服务无法进一步区分。