Android之TrafficStats实现流量实时监测
发布日期:2021-06-29 14:04:02 浏览次数:2 分类:技术文章

本文共 12300 字,大约阅读时间需要 41 分钟。

---恢复内容开始---
TrafficStats类是由Android提供的一个从你的手机开机开始,累计到现在使用的流量总量,或者统计某个或多个进程或应用所使用的流量,当然这个流量包括的Wifi和移动数据网Gprs。这里只针对手机所使用的流量作介绍,至于统计某个进程应用使用的流量,道理都差不多,小伙伴们可以自己查下文档。首先先介绍一下TrafficStats常用的一些方法:
TrafficStats.getTotalRxBytes() ——获取从此次开机起总接受流量(流量是分为上传与下载两类的,当然其实这里还有本地文件之间数据交换的流量,这个暂且不说,等下说明一下我遇到的问题);
TrafficStats.getTotalTxBytes()——获取从此次开机起总发送流量;
TrafficStats.getMobileRxBytes()——获取从此次开机起不包括Wifi的接受流量,即只统计数据网Gprs接受的流量;
TrafficStats.getMobileTxBytes()——获取从此次开机起不包括Wifi的发送流量,即只统计数据网Gprs发送的流量;
于是,小伙伴们可以用getTotalRxBytes() - getMobileRxBytes()获取手机Wifi的接受流量,同理获得Wifi的发送流量。
那么,现在问题来了(不说挖掘机,毕竟蓝翔强):我上面所说的几个方法都是统计从手机开机到现在所使用的总流量,而我需要实现的是检测手机的实时流量使用,或者说我还要算出此刻的网速。那该咋办呢?
这当然也难不了小伙伴们的,我是这样实现的:先获取此刻的总流量,譬如说00:00:00时刻的总使用流量,然后再统计00:00:01时刻的总使用流量,那么两者相减便是这1秒钟所使用的流量,当然你也可以设定为零点几秒。我这里是用线程来实现的,当然你们也可以用Timer,定时器之类的途径实现。
1.先写一个方法,用于统计Wifi下使用的流量:
public double getWifiTraffic(double time){
double rtotalGprs = TrafficStats.getTotalRxBytes();
double ttotalGprs = TrafficStats.getTotalTxBytes();
double rgprs = TrafficStats.getMobileRxBytes();
double tgprs = TrafficStats.getMobileTxBytes();
double rwifi = rtotalGprs - rgprs;
double twifi = ttotalGprs - tgprs;
totalWifi = rwifi + twifi;
return totalWifi;
}
2.用一个TextView来显示一下我们统计的流量数据:
 
3.然后我们新建一个线程用handler更新UI:
new Thread(new Runnable() {
@Override
public void run() {
while(true){
//获取当前时刻
double currentTime = System.currentTimeMillis();
//
getWifiTraffic(currentTime);
获取当前时刻的Wifi流量
double totalWifi01 = getWifiTraffic(currentTime);
//让线程休眠1秒钟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取1秒钟之后的时刻
double frontTime = System.currentTimeMillis();
// 获取一秒钟之后时刻所对应的Wifi使用流量
double totalWifi02 = getWifiTraffic(frontTime);
//两者相减得到这1秒钟所产生的Wifi流量
double errorTraffic = totalWifi02 - totalWifi01;
//这里之所以有一个流量<512b,不将其计入流量统计的原因就是由于我前面提及的本地进程产生的本地流量,如果不减的话,你会发现Android会把不联网状态下
//本地进程之间交互的本地流量也计算进去,我测试了一下大概在每秒钟200b左右
if(errorTraffic < 512){
errorTraffic = 1;
}
//将byte转化为为Mb,1048576=1024*1024,只不过在实际统计中计算会有少许偏差,小伙伴们可根据实际情况微调
wf += errorTraffic/1048576;
wifiTraffic = df.format(wf);
//
Log.i("使用的流量", wifiTraffic + "");
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
}
}).start();
 
final Handler handler = new Handler{ 
public void handleMessage(Message msg){
super.handleMessage(msg);
if(msg.what == 1){
//当流量小于1时,由于0.5这样的数我们会看到手机上会显示为.5,因此在前面加一个0以显示完整
if(Double.parseDouble(wifiTraffic) < 1){
tv.setText("0" + wifiTraffic + "MB");
}
else{
tv.setText(wifiTraffic + "MB");
}
}
}
};
下面贴一下整段代码:
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.TrafficStats;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
double totalWifi;
public static String wifiTraffic ;
public static double wf =0;
private TextView textView;
private WifiManager wifiManager;
public static int wifiStr;
DecimalFormat df = new DecimalFormat(".##");
private TextView tv;
private Handler handler1= null;
int hours = 0,minutes = 0,seconds = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textView);
wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
wifiStr = wifiManager.getWifiState();
if(wifiStr != 3){
Toast.makeText(this, "Wifi未连接", 1000).show();
}
if(wifiStr == 3){
final Handler handler = new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
if(msg.what == 1){
if(Double.parseDouble(wifiTraffic) < 1){
Log.i("wifiTraffic", wifiTraffic);
textView.setText("0" + wifiTraffic + "MB");
}
else{
textView.setText(wifiTraffic + "MB");
}
}
}
};
tv = (TextView)findViewById(R.id.tv3);
if(wifiStr == 3){
handler1 = new Handler(){
public void handleMessage(Message msg1){
super.handleMessage(msg1);
if(msg1.what == 1){
tv.setText(new DecimalFormat("00").format(hours) + ":" + 
new DecimalFormat("00").format(minutes) + ":" + new DecimalFormat("00").format(seconds));
}
}
};
}
new Thread(new Runnable() {
public void run(){
for(int i = 0;;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
seconds++;
Message msg1 = new Message();
msg1.what = 1;
handler1.sendMessage(msg1);
if(seconds == 60){
seconds = 0;
minutes++;
if(minutes == 60){
minutes = 0;
hours++;
}
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true){
double currentTime = System.currentTimeMillis();
//
getWifiTraffic(currentTime);
double totalWifi01 = getWifiTraffic(currentTime);;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
double frontTime = System.currentTimeMillis();
//
getWifiTraffic(frontTime);
double totalWifi02 = getWifiTraffic(frontTime);
double errorTraffic = totalWifi02 - totalWifi01;
if(errorTraffic < 512){
errorTraffic = 1;
}
wf += errorTraffic/1111500;
wifiTraffic = df.format(wf);
//
Log.i("使用的流量", wifiTraffic + "");
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
}
}).start();
}
}
public double getWifiTraffic(double time){
double rtotalGprs = TrafficStats.getTotalRxBytes();
double ttotalGprs = TrafficStats.getTotalTxBytes();
double rgprs = TrafficStats.getMobileRxBytes();
double tgprs = TrafficStats.getMobileTxBytes();
double rwifi = rtotalGprs - rgprs;
double twifi = ttotalGprs - tgprs;
totalWifi = rwifi + twifi;
return totalWifi;
//totalWifi = rtotalGprs + ttotalGprs;
}

}

1、TrafficStats类的使用

以下结论,是自己真机实测的结果,与自己在网上看到的不同,大家可自测验证。

(1)getMobile...方法,获取Gprs/3G流量

(2)getTotal...方法,获取Gprs/3G+Wifi的流量

以上两类方法统计的都是,从打开网络开始,到关闭网络,这一段时间内使用的流量。例如:10点打开,11点关闭,那么getMobileRxBytes方法,回返的是这段时间内Gprs/3G接受到的字节数。

(3)getUid...方法,获取某个网络UID的流量。这类方法,返回的是,从开机到关机,某个网络UID(我理解就是某个应用,如果不对,请在评论中指正)使用的Gprs/3G+Wifi的流量

2、getUid...方法的使用

以下这段代码是网上找的,出处找不到了,希望原作者不要介意啊

List
packinfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS); for (PackageInfo info : packinfos) { String[] premissions = info.requestedPermissions; if (premissions != null && premissions.length > 0) { for (String premission : premissions) { if ("android.permission.INTERNET".equals(premission)) { // System.out.println(info.packageName+"访问网络"); int uid = info.applicationInfo.uid; long rx = TrafficStats.getUidRxBytes(uid); long tx = TrafficStats.getUidTxBytes(uid); if (rx < 0 || tx < 0) { System.out.println(info.packageName + "没有产生流量"); } else { System.out.println(info.packageName + "的流量信息:"); System.out.println("下载的流量" + Formatter.formatFileSize(this, rx)); System.out.println("上传的流量" + Formatter.formatFileSize(this, tx)); } } } System.out.println("---------"); } }
3、获取流量信息的Service类

(1)因为两个广播都需要动态注册,所以写成了Service

(2)getMobile...和getTotal...方法获取的都是从打开网络开始,到关闭网络,这一段时间内使用的流量。

因此要在网络正在关闭时获取的就是这段时间的流量,WifiManager.WIFI_STATE_DISABLING表示的就是这个状态

(3)Gprs/3G貌似没有类似的状态,可以被监控到,只有,State.CONNECTED和State.DISCONNECTED。但是处于State.DISCONNECTED这个状态时,getMobile...方法获取到的值就都是0了

所有,我不得不在State.CONNECTED这个状态开始时,开启线程用于获取Gprs/3G的流量,直到我获取的到数据为0时,保存上一次的数据。

如果大家有更好的方法,请务必告诉我啊!

package forrest.forassist.service;    import android.app.Service;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter;  import android.net.ConnectivityManager;  import android.net.NetworkInfo;  import android.net.NetworkInfo.State;  import android.net.TrafficStats;  import android.net.wifi.WifiManager;  import android.os.IBinder;  import android.text.format.Formatter;  import android.util.Log;  import forrest.forassist.db.MySQLiteDatabase;  import forrest.forassist.utils.Util;    public class TrafficService extends Service {        private TrafficReceiver tReceiver;      private WifiManager wifiManager;      private ConnectivityManager cManager;        public IBinder onBind(Intent intent) {          return null;      }        public void onCreate() {          // WifiManager,ConnectivityManager          wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);          cManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);          // 注册TrafficReceiver          tReceiver = new TrafficReceiver();          IntentFilter filter = new IntentFilter();          filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);          filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);          registerReceiver(tReceiver, filter);          super.onCreate();      }        public int onStartCommand(Intent intent, int flags, int startId) {            return super.onStartCommand(intent, flags, startId);      }        private class TrafficReceiver extends BroadcastReceiver {          private String action = "";          private static final String TAG = "TrafficReceiver";          long mobileRx;          long mobileTx;            public void onReceive(Context context, Intent intent) {              action = intent.getAction();              if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {                  if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLING) {                      Log.i(TAG, "WIFI_STATE_DISABLING");                      long wifiDown = TrafficStats.getTotalRxBytes() - TrafficStats.getMobileRxBytes();                      long wifiUp = TrafficStats.getTotalTxBytes() - TrafficStats.getMobileTxBytes();                      MySQLiteDatabase sqLite = new MySQLiteDatabase(context); // 打开数据库                      sqLite.insertWifi(Util.todayDate, wifiDown, wifiUp);                      sqLite.closeDB();                      Log.i(TAG, "wifi下载流量" + Formatter.formatFileSize(context, wifiDown));                      Log.i(TAG, "wifi上传流量" + Formatter.formatFileSize(context, wifiUp));                  }              } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {                  Log.i(TAG, "CONNECTIVITY_ACTION");                  NetworkInfo networkInfo = cManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);                  State state = networkInfo.getState();                  if (state == State.CONNECTED) {                      Log.i(TAG, "State.CONNECTED");                      // 开始不断获取最近的流量信息,值为0时,跳过                      new Thread() {                          public void run() {                              long mobileRxType = TrafficStats.getMobileRxBytes();                              long mobileTxType = TrafficStats.getMobileTxBytes();                              if (mobileRxType + mobileTxType != 0) {                                  try {                                      mobileRx = mobileRxType;                                      mobileTx = mobileTxType;                                      Log.i(TAG, "mobileRx:" + mobileRx);                                      Log.i(TAG, "mobileTx:" + mobileTx);                                      Thread.sleep(1000);                                      run();                                  } catch (InterruptedException e) {                                      e.printStackTrace();                                  }                              } else {                                  // 写入数据库                                  Log.i(TAG, "写入数据库");                                  MySQLiteDatabase sqLite = new MySQLiteDatabase(TrafficService.this);                                  sqLite.insertGprs(Util.todayDate, mobileRx, mobileTx);                                  sqLite.closeDB();                              }                          };                      }.start();                  }               }          }      }        public void onDestroy() {          unregisterReceiver(tReceiver);          super.onDestroy();      }  }

转载地址:https://chenyu.blog.csdn.net/article/details/52305065 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android之android.os.NetworkOnMainThreadException异常
下一篇:Android之中如何用广播ConnectivityManager.CONNECTIVITY_ACTION监听网络变化,将其显示在通知栏上

发表评论

最新留言

很好
[***.229.124.182]2024年05月01日 05时43分29秒