Android 统计流量数据

news/2024/12/4 23:54:41/

【流量统计】

使用到的类:TrafficStats(设备启动以来流量的统计信息)
NetworkStatsManager(网络历史数据)
参考链接:
(1)https://developer.android.google.cn/reference/android/net/TrafficStats.html
(2)https://developer.android.google.cn/reference/android/app/usage/NetworkStatsManager.html

1、TrafficStats类是读取Linux提供的文件对象系统类型的文本进行解析。
android.net.TrafficStats类中,提供了多种静态方法,可以直接调用获取,返回类型均为 long型,如果返回等于-1代表 UNSUPPORTED 当前设备不支持统计。

TrafficStats能够获取设备的数据流量和总的网络流量消耗(一般情况下也就得到Wi-Fi下的流量信息);
可以查询uid对应的流量信息,而uid可以通过应用的包名查询到,因此能够查询某个应用的流量统计信息(不考虑shareuid)。
非常方便的是,它的使用不需要特别的权限。另一方面它也一些限制:

(1)无法获取应用的数据流量消耗
从文档中仅能获取到指定uid的流量,但无法区分不同网络类型下的消耗
间接方法是通过监听网络切换,做好流量记录(但是要保证你的应用一直存活,且一定准确接收到网络切换信息),基本不可用。
(2)无法获取某个时间段内的流量消耗
从API文档中看,函数参数没有与时间相关的信息。而且重要的一点是,TrafficStats类中记录的是设备重启以来的流量统计信息。
因为TrafficStats 类,底层还是读取/proc/net/xt_qtaguid/stats 对内容进行解析,将得到对应的结果返回上层。

Android系统中封装了一套流量数据API,这些API可以很好的管理Android系统流量使用情况。我们可以基于这些Android API来实现管理手机流量的功能。
这些API很好的封装在了android.net包下的TrafficStats中,主要的方法有:

/*** static long getMobileRxBytes()//获取通过Mobile连接收到的字节总数,但不包含WiFi * static long getMobileRxPackets()//获取Mobile连接收到的数据包总数 * static long getMobileTxBytes()//Mobile发送的总字节数,* static long getMobileTxPackets()//Mobile发送的总数据包数 * static long getTotalRxBytes()//获取总的接受字节数,包含Mobile和WiFi等 * static long getTotalRxPackets()//总的接受数据包数,包含Mobile和WiFi等 * static long getTotalTxBytes()//总的发送字节数,包含Mobile和WiFi等 * static long getTotalTxPackets()//发送的总数据包数,包含Mobile和WiFi等 * static long getUidRxBytes(int uid)//获取某个网络UID的接受字节数 * static long getUidTxBytes(int uid) //获取某个网络UID的发送字节数*/

2、NetworkStatsManager类是在Android 6.0(API23)中新增加的类,提供网络使用历史统计信息,同时特别强调了可查询指定时间间隔内的统计信息。
NetworkStatsManager类克服了TrafficStats的查询限制,而且统计信息也不再是设备重启以来的数据。但它也有自己的限制和缺点。
(1)权限限制
NetworkStatsManager的使用需要额外的权限,”android.permission.PACKAGE_USAGE_STATS”是系统权限,需要主动引导用户开启应用的“有权查看使用情况的应用”(使用记录访问权限)权限,后面会有代码示例。
(2)文档不完善
不好说是文档不全,还是我没找对。首先文档中没有给出类的实例对象的构造方法,一开始还是反射获取的,后来才发现可以通过获取系统服务方式得到。另外queryDetailsForUid函数中设置的时间间隔不太有用,没能及时的获取流量统计信息,而是有两个小时的时间间隔。还好可以在querySummary函数中获得。

看看部分函数(非静态):
//查询指定网络类型在某时间间隔内的总的流量统计信息
NetworkStats.BucketquerySummaryForDevice(intnetworkType,StringsubscriberId,longstartTime,longendTime)
//查询某uid在指定网络类型和时间间隔内的流量统计信息
NetworkStats.queryDetailsForUid(intnetworkType,StringsubscriberId,longstartTime,longendTime,intuid)
//查询指定网络类型在某时间间隔内的详细的流量统计信息(包括每个uid)
NetworkStats.queryDetails(intnetworkType,StringsubscriberId,longstartTime,longendTime)

一、TrafficStats获取某个应用的流量的统计(根据包名)

1.根据包名获取相应的UID
/**
* 获取当前应用uid
* @return
*/
public int getUid() {
try {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
return ai.uid;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}

2.根据UID获取相应的流量的统计
TrafficInfo tr=new TrafficInfo(getApplicationContext());
int uid=tr.getUid();
Log.e(“asdf”,uid+"");
Log.e(“asdf”,tr.getRcvTraffic()+"-下载流量-"+tr.getSndTraffic()+"-上传流量-"+tr.getTrafficInfo()+"-总流量-");

3.完整代码

package com.rzt.qualitytest.utils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

/**

  • 应用的流量信息
    */
    public class TrafficInfo {
    private static final int UNSUPPORTED = -1;
    private static final String LOG_TAG = “test”;
    private static TrafficInfo instance;
    static int uid=0;
    private long preRxBytes = 0;
    private Timer mTimer = null;

    //更新频率(每几秒更新一次,至少1秒)
    private final int UPDATE_FREQUENCY = 1;
    private int times = 1;
    private Context mContext;

    public TrafficInfo(Context mContext, int uid) {
    this.uid = uid;
    this.mContext=mContext;
    }

    public TrafficInfo(Context mContext) {
    this.mContext=mContext;
    }

    /**

    • 获取总流量
    • @return
      */
      public long getTrafficInfo() {
      long rcvTraffic = UNSUPPORTED; // 下载流量
      long sndTraffic = UNSUPPORTED; // 上传流量
      rcvTraffic = getRcvTraffic();
      sndTraffic = getSndTraffic();
      if (rcvTraffic == UNSUPPORTED || sndTraffic == UNSUPPORTED)
      return UNSUPPORTED;
      else
      return rcvTraffic + sndTraffic;
      }

    /**

    • 获取下载流量 某个应用的网络流量数据保存在系统的/proc/uid_stat/$UID/tcp_rcv | tcp_snd文件中

    • @return
      */
      public long getRcvTraffic() {
      long rcvTraffic = UNSUPPORTED; // 下载流量
      if(uid==0){
      uid=getUid();
      }
      rcvTraffic = TrafficStats.getUidRxBytes(uid);
      if (rcvTraffic == UNSUPPORTED) {
      // 不支持的查询
      return UNSUPPORTED;
      }
      Log.i(“test”, rcvTraffic + “–1”);

      RandomAccessFile rafRcv = null, rafSnd = null; // 用于访问数据记录文件
      String rcvPath = “/proc/uid_stat/” + uid + “/tcp_rcv”;
      try {
      rafRcv = new RandomAccessFile(rcvPath, “r”);
      rcvTraffic = Long.parseLong(rafRcv.readLine()); // 读取流量统计
      } catch (FileNotFoundException e) {
      Log.e(LOG_TAG, "FileNotFoundException: " + e.getMessage());
      rcvTraffic = UNSUPPORTED;
      } catch (IOException e) {
      Log.e(LOG_TAG, "IOException: " + e.getMessage());
      e.printStackTrace();
      } finally {
      try {
      if (rafRcv != null)
      rafRcv.close();
      if (rafSnd != null)
      rafSnd.close();
      } catch (IOException e) {
      Log.w(LOG_TAG, "Close RandomAccessFile exception: " + e.getMessage());
      }
      }
      Log.i(“test”, rcvTraffic + “–2”);
      return rcvTraffic;
      }

    /**

    • 获取上传流量

    • @return
      */
      public long getSndTraffic() {
      long sndTraffic = UNSUPPORTED; // 上传流量
      if(uid==0){
      uid=getUid();
      }
      sndTraffic = TrafficStats.getUidTxBytes(uid);
      if (sndTraffic == UNSUPPORTED) {
      // 不支持的查询
      return UNSUPPORTED;
      }

      RandomAccessFile rafRcv = null, rafSnd = null; // 用于访问数据记录文件
      String sndPath = “/proc/uid_stat/” + uid + “/tcp_snd”;
      try {
      rafSnd = new RandomAccessFile(sndPath, “r”);
      sndTraffic = Long.parseLong(rafSnd.readLine());
      } catch (FileNotFoundException e) {
      Log.e(LOG_TAG, "FileNotFoundException: " + e.getMessage());
      sndTraffic = UNSUPPORTED;
      } catch (IOException e) {
      Log.e(LOG_TAG, "IOException: " + e.getMessage());
      e.printStackTrace();
      } finally {
      try {
      if (rafRcv != null)
      rafRcv.close();
      if (rafSnd != null)
      rafSnd.close();
      } catch (IOException e) {
      Log.w(LOG_TAG, "Close RandomAccessFile exception: " + e.getMessage());
      }
      }
      return sndTraffic;
      }

    /**

    • 获取当前下载流量总和
    • @return
      */
      public static long getNetworkRxBytes() {
      return TrafficStats.getTotalRxBytes();
      }

    /**

    • 获取当前上传流量总和
    • @return
      */
      public static long getNetworkTxBytes() {
      return TrafficStats.getTotalTxBytes();
      }

    /**

    • 获取当前网速

    • @return
      */
      public double getNetSpeed() {
      long curRxBytes = getNetworkRxBytes();
      if (preRxBytes == 0)
      preRxBytes = curRxBytes;
      long bytes = curRxBytes - preRxBytes;
      preRxBytes = curRxBytes;
      //int kb = (int) Math.floor(bytes / 1024 + 0.5);
      double kb = (double)bytes / (double)1024;
      BigDecimal bd = new BigDecimal(kb);

      return bd.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
      }

    /**

    • 开启流量监控
      */
      public void startCalculateNetSpeed() {
      preRxBytes = getNetworkRxBytes();
      if (mTimer != null) {
      mTimer.cancel();
      mTimer = null;
      }
      if (mTimer == null) {
      mTimer = new Timer();
      mTimer.schedule(new TimerTask() {
      @Override
      public void run() {
      if(times == UPDATE_FREQUENCY){
      Message msg = new Message();
      msg.what = 1;
      //msg.arg1 = getNetSpeed();
      msg.obj = getNetSpeed();
      mHandler.sendMessage(msg);
      times = 1;
      } else {
      times++;
      }
      }
      }, 1000, 1000); // 每秒更新一次
      }
      }

    public void stopCalculateNetSpeed() {
    if (mTimer != null) {
    mTimer.cancel();
    mTimer = null;
    }
    }

    /**

    • 获取当前应用uid
    • @return
      */
      public int getUid() {
      try {
      PackageManager pm = mContext.getPackageManager();
      ApplicationInfo ai = pm.getApplicationInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
      return ai.uid;
      } catch (NameNotFoundException e) {
      e.printStackTrace();
      }
      return -1;
      }
      }

4.具体实现

(1)创建实体类TrafficInfo
为了更好的提现java面向对象的思想,我将获取的手机应用程序的信息封装成一个javabean,这个javabean实体类封装了应用程序的图标,包名,名称,用户id等信息,

具体实现代码如下:
package cn.lyz.mobilesafe.domain;
import android.graphics.drawable.Drawable;
/*** 流量信息*/
public class TrafficInfo {//应用图标private Drawable icon;//app名称private String appname;//包名private String packname;//uidprivate int uid;public TrafficInfo() {super();// TODO Auto-generated constructor stub}public TrafficInfo(Drawable icon, String appname, String packname, int uid) {super();this.icon = icon;this.appname = appname;this.packname = packname;this.uid = uid;}public Drawable getIcon() {return icon;}public void setIcon(Drawable icon) {this.icon = icon;}public String getAppname() {return appname;}public void setAppname(String appname) {this.appname = appname;}public String getPackname() {return packname;}public void setPackname(String packname) {this.packname = packname;}public int getUid() {return uid;}public void setUid(int uid) {this.uid = uid;}@Overridepublic String toString() {return "TrafficInfo [icon=" + icon + ", appname=" + appname+ ", packname=" + packname + ", uid=" + uid + "]";}
}

(2)获取手机安装的应用程序的工具类TrafficManagerService
这个封装了主要封装了两个方法,一个是查询能够启动的应用程序方法getLauncherTrafficInfos,
一个是获取拥有internet权限的应用列表的方法getInternetTrafficInfos,两个方法的返回值都是一个应用程序列表集合List。

具体实现代码如下:
package cn.lyz.mobilesafe.engine;import java.util.ArrayList;
import java.util.List;import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import cn.lyz.mobilesafe.domain.TrafficInfo;/*** 获取手机安装的应用程序的的引擎工具类*/
public class TrafficManagerService {private PackageManager pm;public TrafficManagerService(Context context) {super();pm = context.getPackageManager();}/*** 查询能够启动的应用程序* @return*/public List<TrafficInfo> getLauncherTrafficInfos(){List<TrafficInfo> trafficInfos = new ArrayList<TrafficInfo>();//查询能够启动的应用程序  Intent intent = new Intent();intent.setAction(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_LAUNCHER);//ResolveInfo  就类似于一个IntentFilterList<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);for(ResolveInfo info:resolveInfos){ApplicationInfo appInfo = info.activityInfo.applicationInfo;Drawable appicon = appInfo.loadIcon(pm);String appname = appInfo.loadLabel(pm).toString();String packageName = appInfo.packageName;int uid = appInfo.uid;trafficInfos.add(new TrafficInfo(appicon, appname, packageName, uid));}return trafficInfos;}/*** 获取拥有internet权限的应用列表* @return*/public List<TrafficInfo> getInternetTrafficInfos(){List<TrafficInfo> trafficInfos = new ArrayList<TrafficInfo>();//获取手机中安装的并且具有权限的应用List<PackageInfo> installedPackages = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);for(PackageInfo info : installedPackages){//获取权限数组String[] permissions = info.requestedPermissions;if(permissions != null && permissions.length > 0){for(String permission : permissions){if(permission.equals(Manifest.permission.INTERNET)){ApplicationInfo applicationInfo = info.applicationInfo;Drawable icon = applicationInfo.loadIcon(pm);String appname = applicationInfo.loadLabel(pm).toString();String packagename = applicationInfo.packageName;int uid = applicationInfo.uid;TrafficInfo trafficInfo = new TrafficInfo(icon, appname, packagename, uid);trafficInfos.add(trafficInfo);}}}}return trafficInfos;}
}

(3)创建文本格式化工具类TextFormat
当我们在Android系统中获取到流量信息时,有些流量的单位是byte,有些流量的单位是kb,为了统一显示这些流量信息单位,我在这里写了一个格式化流量单位的工具类。

具体实现代码如下:
package cn.lyz.mobilesafe.utils;import java.text.DecimalFormat;/*** 文本格式化工具类*/
public class TextFormat {/*** 格式化数据* @param data* @return*/public static String formatByte(long data){DecimalFormat format = new DecimalFormat("##.##");if(data < 1024){return data+"bytes";}else if(data < 1024 * 1024){return format.format(data/1024f) +"KB";}else if(data < 1024 * 1024 * 1024){return format.format(data/1024f/1024f) +"MB";}else if(data < 1024 * 1024 * 1024 * 1024){return format.format(data/1024f/1024f/1024f) +"GB";}else{return "超出统计范围";}}
}

(4)程序入口TrafficManagerActivity

具体实现代码如下:
package com.lyz.traffic.state.activity;import java.util.List;
import java.util.Timer;
import java.util.TimerTask;import android.app.Activity;
import android.content.Context;
import android.net.TrafficStats;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import cn.lyz.mobilesafe.domain.TrafficInfo;
import cn.lyz.mobilesafe.engine.TrafficManagerService;
import cn.lyz.mobilesafe.utils.TextFormat;/*** 流量管理*/
public class TrafficManagerActivity extends Activity {//类成员字段protected static final int SUCCESS_GET_TRAFFICINFO = 0;protected static final int REFRESH_TRAFFIC = 1;private TextView tv_traffic_manager_mobile;private TextView tv_traffic_manager_wifi;private ListView lv_traffic_manager_content;private TrafficManagerService managerService;private List<TrafficInfo> trafficInfos;private List<TrafficInfo> realTrafficInfos;private TrafficManagerAdapter mAdapter;//实现定时操作//在这个示例程序中,我们需要一个定时器来实时获取手机流量数据,来实现动态实时效果的呈现,//所以,这里用到了Timer和TimerTask两个工具类,来实现2秒钟向主线程发送一次message消息,由Handler来执行刷新界面显示的效果。private Timer timer;private TimerTask timerTask = new TimerTask() {@Overridepublic void run() {Message msg = new Message();msg.what = REFRESH_TRAFFIC;mHandler.sendMessage(msg);}};//Handler实现//我们通过一个Hanlder来实现主线程与子线程的交互操作,将子线程处理的结果数据,通过Handler与Message机制传递到主线程。private Handler mHandler = new Handler(){public void handleMessage(android.os.Message msg) {switch (msg.what) {case SUCCESS_GET_TRAFFICINFO:mAdapter = new TrafficManagerAdapter(TrafficManagerActivity.this);lv_traffic_manager_content.setAdapter(mAdapter);timer = new Timer();timer.schedule(timerTask, 0,2000);break;case REFRESH_TRAFFIC:if(mAdapter != null){mAdapter.notifyDataSetChanged();}break;default:break;}};};//onCreate方法主要实现的功能是初始化页面控件,设置控件事件,在子线程中实现获取手机流量信息等操作。@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.traffic_manager);tv_traffic_manager_mobile = (TextView) findViewById(R.id.tv_traffic_manager_mobile);tv_traffic_manager_wifi = (TextView) findViewById(R.id.tv_traffic_manager_wifi);lv_traffic_manager_content = (ListView) findViewById(R.id.lv_traffic_manager_content);tv_traffic_manager_mobile.setText(TextFormat.formatByte(getMobileTotal()));tv_traffic_manager_wifi.setText(TextFormat.formatByte(getWifiTotal()));managerService = new TrafficManagerService(this);new Thread(new Runnable() {@Overridepublic void run() {//trafficInfos = managerService.getLauncherTrafficInfos();realTrafficInfos = managerService.getInternetTrafficInfos();
//				realTrafficInfos = new ArrayList<TrafficInfo>();
//				for(TrafficInfo info : trafficInfos){
//					if(TrafficStats.getUidRxBytes(info.getUid()) == -1 && TrafficStats.getUidTxBytes(info.getUid())== -1){
//						
//					}else{
//						realTrafficInfos.add(info);
//					}
//				}Message msg = new Message();msg.what = SUCCESS_GET_TRAFFICINFO;msg.obj = trafficInfos;mHandler.sendMessage(msg);}}).start();//2g/3g接收的流量//TrafficStats.getMobileRxBytes();//2g/3g接收的包信息//TrafficStats.getMobileRxPackets();//2g/3g上传的流量//TrafficStats.getMobileTxBytes();//2g/3g上传的包信息//TrafficStats.getMobileTxPackets();//手机总共接收的流量//TrafficStats.getTotalRxBytes();//手机总共上传的流量//TrafficStats.getTotalTxBytes();//得到某个应用程程序接收的流量//TrafficStats.getUidRxBytes(uid);//得到某个应用程程序接收的流量//TrafficStats.getUidTxBytes(uid);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}/*** 获取手机2g/3g总流量* @return*/private long getMobileTotal(){long mobile_rx = TrafficStats.getMobileRxBytes();long mobile_tx = TrafficStats.getMobileTxBytes();return mobile_rx + mobile_tx;}/*** 获取手机总流量* @return*/private long total(){return TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();}/*** 获取WIFI总流量* @return*/private long getWifiTotal(){return total() - getMobileTotal();}//自定义适配器TrafficManagerAdapter//这是个内部类,继承自BaseAdapter,主要实现了将获取到的数据显示到界面上的操作,我们这里用到了ListView的ViewHolder缓存技术。static class ViewHolder{ImageView iv_appicon;TextView tv_appname;TextView tv_apptx;TextView tv_apprx;TextView tv_apptarffic;}private class TrafficManagerAdapter extends BaseAdapter{private LayoutInflater mLayoutInflater;public TrafficManagerAdapter(Context context){mLayoutInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn realTrafficInfos.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn realTrafficInfos.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = null;ViewHolder holder = null;if(convertView != null){view = convertView;holder = (ViewHolder) view.getTag();}else{view = mLayoutInflater.inflate(R.layout.traffic_manager_item, null);holder = new ViewHolder();holder.iv_appicon = (ImageView) view.findViewById(R.id.iv_appicon);holder.tv_appname = (TextView) view.findViewById(R.id.tv_appname);holder.tv_apptx = (TextView) view.findViewById(R.id.tv_apptx);holder.tv_apprx = (TextView) view.findViewById(R.id.tv_apprx);holder.tv_apptarffic = (TextView) view.findViewById(R.id.tv_apptarffic);view.setTag(holder);}TrafficInfo info = realTrafficInfos.get(position);holder.iv_appicon.setImageDrawable(info.getIcon());String name = info.getAppname();if(name.length() > 8){name = name.substring(0, 7)+"...";}holder.tv_appname.setText(name);int uid = info.getUid();long tx = TrafficStats.getUidTxBytes(uid);if(tx < 0){tx = 0;}long rx = TrafficStats.getUidRxBytes(uid);if(rx < 0){rx = 0;}long total = tx + rx;holder.tv_apptarffic.setText(TextFormat.formatByte(total));holder.tv_apptx.setText("上传:"+TextFormat.formatByte(tx));holder.tv_apprx.setText("下载:"+TextFormat.formatByte(rx));return view;}}//onDestroy方法,在这个回调方法中实现资源释放的操作。@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if(timer != null){timer.cancel();timer = null;}if(timerTask != null){timerTask.cancel();timerTask = null;}}
}

二、NetworkStatsManager使用代码示例

1.权限设置
(1)AndroidManifest中添加权限声明

(2)代码中主动引导用户开启权限
这里没有说明READ_PHONE_STATE的主动获取,大家根据自己的targetSdkVersion设置

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

2.查看设备和某应用的流量统计
(1)获取NetworkStatsManager示例对象
NetworkStatsManager networkStatsManager = (NetworkStatsManager) getSystemService(NETWORK_STATS_SERVICE);

(2)查询设备总的流量统计信息
NetworkStats.Bucket bucket = null;
// 获取到目前为止设备的Wi-Fi流量统计
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, “”, 0, System.currentTimeMillis());
Log.i(“Info”, "Total: " + (bucket.getRxBytes() + bucket.getTxBytes()));

(3)查询某应用(uid)的数据流量统计信息
// 获取subscriberId
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String subId = tm.getSubscriberId();

NetworkStats summaryStats;
long summaryRx = 0;
long summaryTx = 0;
NetworkStats.Bucket summaryBucket = new NetworkStats.Bucket();
long summaryTotal = 0;summaryStats = networkStatsManager.querySummary(ConnectivityManager.TYPE_MOBILE, subId, getTimesMonthmorning(), System.currentTimeMillis());
do {summaryStats.getNextBucket(summaryBucket);int summaryUid = summaryBucket.getUid();if (uid == summaryUid) {summaryRx += summaryBucket.getRxBytes();summaryTx += summaryBucket.getTxBytes();}Log.i(MainActivity.class.getSimpleName(), "uid:" + summaryBucket.getUid() + " rx:" + summaryBucket.getRxBytes() +" tx:" + summaryBucket.getTxBytes());summaryTotal += summaryBucket.getRxBytes() + summaryBucket.getTxBytes();
} while (summaryStats.hasNextBucket());

3.附赠实用函数
(1)应用包名查uid
public static int getUidByPackageName(Context context, String packageName) {
int uid = -1;
PackageManager packageManager = context.getPackageManager();
try {
PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA);
uid = packageInfo.applicationInfo.uid;
Log.i(MainActivity.class.getSimpleName(), packageInfo.packageName + " uid:" + uid);
} catch (PackageManager.NameNotFoundException e) {
}
return uid;
}

(2)获得本月第一天0点时间
public static long getTimesMonthMorning() {
Calendar cal = Calendar.getInstance();
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
return cal.getTimeInMillis();
}

【流量监听】

监听流量,保存到本地,合适的时间发送到服务器

下面是业务逻辑Service:

package com.example.app;

import java.util.Calendar;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.TrafficStats;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service implements Runnable {
private static long interval = 10006060*1;//间隔时间,每隔一段时间记录一次3g/2g产生的流量,默认是1小时
private long sleepTime = (long) (1000 *60 *0.1);//停留的时间

private static int hour = 18;//发送流量到服务器的时间--小时
private static int minute = 30;//发送流量到服务器的时间--分钟
public static boolean isrun = false;
private long lastTime = 0;//上一次保存流量的时间
Context con;public MyService() {
}/*** @param interval*            间隔时间,每隔一段时间记录一次3g/2g产生的流量,默认是1小时*/
public MyService(long interval) {this.interval = interval;
}/*** @param interval  间隔时间,每隔一段时间记录一次3g/2g产生的流量,默认是1小时* @param hour 发送流量到服务器的时间--小时  默认是18* @param minute 发送流量到服务器的时间--分钟 默认是30*/
public MyService(long interval,int hour,int minute){this.interval = interval;this.hour = hour;this.minute = minute;
}/*** @param interval  间隔时间,每隔一段时间记录一次3g/2g产生的流量,默认是1小时* @param hour 发送流量到服务器的时间--小时  默认是18* @param minute 发送流量到服务器的时间--分钟 默认是30*/
public static void init(long interval,int hour,int minute){MyService.interval = interval;MyService.hour = hour;MyService.minute = minute;
}@Override
public void run() {// TODO Auto-generated method stubwhile (isrun) {// 每隔一段时间保持当前流量值long nowtime = System.currentTimeMillis();if (nowtime - lastTime >= interval) {lastTime = nowtime;long i1 = TrafficStats.getMobileRxBytes();long total = Storage.getLong(con, Storage.TotalMobileRxBytes);long last = Storage.getLong(con, Storage.LastMobileRxBytes);long now = total + i1 - last;Storage.saveLong(con, Storage.TotalMobileRxBytes, now);Storage.saveLong(con, Storage.LastMobileRxBytes, i1);// Toast.makeText(con, now+"", 0).show();Log.i("之前总流量", total + "");Log.i("获取流量", i1 + "");Log.i("上次流量", last + "");Log.i("当前总流量", now + "");} else {try {Thread.sleep(sleepTime);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}/*** 每天定时发送流量到服务器*/
Thread sendThread = new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (isrun) {Calendar c = Calendar.getInstance();int hour1 = c.get(Calendar.HOUR_OF_DAY);int minute1 = c.get(Calendar.MINUTE);if (hour1 == hour && minute == minute1 ) {sendToService();}else if(!Storage.getBlooean(con, Storage.hasSend) &&(hour<hour1 ||( hour == hour1 && minute<minute1)) ){sendToService();   }}}private void sendToService() {System.out.println("开始上传流量到服务器");Storage.saveLong(con, Storage.TotalMobileRxBytes, (long) 0);Storage.saveBoolean(con, Storage.hasSend, true);try {Thread.sleep(1000*60*2);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
});public int onStartCommand(Intent intent, int flags, int startId) {Log.i("MyService--", "onStartCommand");con = this;isrun = true;lastTime = System.currentTimeMillis();Thread t = new Thread(this);if(!t.isAlive())t.start();if(!sendThread.isAlive())sendThread.start();return startId;
};@Override
public void onCreate() {// TODO Auto-generated method stubsuper.onCreate();Log.i("MyService--", "onCreate");
}@Override
public void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();Log.i("MyService--", "onDestroy");isrun = false;stopSelf();System.out.println("停止监听12222222");
}@Override
public IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;
}

}

【Android N - Data Saver】

android n在网络ConnectivityManager api的变动比较大。其中在蜂窝数据有一个流量保护机制,Data Saver。
可以在setting目录下,Data Usage里面可以开启关闭Data saver功能。
开启Data saver后(默认是enable background data usage,启用后台数据使用),会有一些应用列表出来,让你选择是否允许 unrestricted data access(不限制数据使用)。
如果想要关闭background data usage,可以在Data Usage里找cellur data useage(蜂窝数据使用) 选择你的ap,开关background data usage。

1、写receiver来监听开关data saver option changed事件。
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(“MainActivity”,"onReceive "+ intent.getAction());
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
boolean isNetworkMetered = manager.isActiveNetworkMetered();
Log.d(“MainActivity”,"isNetworkMetered = "+ isNetworkMetered);
if(isNetworkMetered){
//通过getRestrictBackgroundStatus()这个API来判断Data Saver是否针对我们的app处于激活状态,
Log.d(“MainActivity”,"getRestrictBackgroundStatus = "+ manager.getRestrictBackgroundStatus());
switch (manager.getRestrictBackgroundStatus()){
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
//关闭了data saver,蜂窝数据不限制。
break;
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
//开启了Data saver 或者 Data saver开启的状态下 enable backgroud data由关到开。
//这时service里后台运行的蜂窝数据不可以使用,假如程序不是activie程序,数据也不可以使用。
break;
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
//Datat saver开启的状态下,allow unrestricted data access 开启了,
//这时蜂窝数据可以使用,即使程序切到后台,activie 程序非他自己,数据也可以使用。
break;
}
}
}
}

2、再在代码里注册一下这个receiver,code如下:
registerReceiver(new MyReceiver(),new IntentFilter(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED));

ConnectivityManager类

ConnectivityManager 是一个网络连接的管理类,里面封装了网络请求的详细信息,
包括WiFi与移动数据流量的开关状态,正在开启与关闭的状态,连接状态等等,很适合做网络监听。
还有一个类WifiManager ,这个类专门用来做WiFi的监听,他的监听效果比ConnectivityManager更加详细丰富,可以检测但是对流量没法生效。

注册广播,写一个类继承自BroadcastReceiver。@Overridepublic void onReceive(Context context, Intent intent) {ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);if (intent.getAction().equals("Android.net.conn.CONNECTIVITY_CHANGE"))    {//移动数据连接上时if (gprs.isConnected()){}//wifi连接上时if (wifi.isConnected()) {// 切换网络,关闭wifi,开启流量if (isShow) {//做一个标记,避免多次弹窗的叠加bug,初始值为true,重要switchNetwork(context);}}//断网时if (!netManager.getGRPS().isConnected() || !netManager.getGRPS().isConnected()) {}}

http://www.ppmy.cn/news/451943.html

相关文章

miui android系统 流量,[Android] 小米云流量最新魔改领100G流量教程

背景&#xff1a;小米Max3出了个云流量&#xff0c;可以支持无卡上网。最近他们天天送100GB流量&#xff0c;看得心痒&#xff0c;拿自己的小米8折腾了一下&#xff0c;居然能领能用。总结一下教程&#xff0c;分享出来给大家耍耍。 测试机型&#xff1a;小米8&#xff0c;开发…

android获取手机流量使用情况

软件流量使用数据保存在 /proc/uid_stat/uid(用户id)/ 下面文件中 /proc/uid_stat/uid/tcp_send 上传流量 /proc/uid_stat/uid/tcp_rcv 下载流量 关键代码如下: //1.获取一个包管理器。 PackageManager pm getPackageManager(); //2.遍历手机操作系统 获取所有…

android手机相册多张上传,一键批量上传手机照片到QQ相册功能 节省手机流量

十一双假期刚刚结束&#xff0c;无论回家还是出游&#xff0c;不管是家里的庭院小景还是一路上的美景扑面&#xff0c;你一定会拿起手机不断按下快门&#xff0c;记录每一个美的瞬间。如今长假归来&#xff0c;我们都希望能够马上和好友一起分享假期的美景趣事。可是&#xff0…

用流量扫码总显示无法连接服务器,手机有流量但无法连接网络?手机数据网络不能访问互联网...

无法访问移动网络(为什么数据网络不能访问互联网&#xff1f;) 无法访问移动网络(为什么数据网络不能访问互联网&#xff1f;) 1.手机关机重启一次&#xff0c;因为可能是你的手机出现了一点反应迟钝连接的情况。 2、因为你的网络连接其实是不稳定的。或者是根本没有连接上…&a…

电脑连手机热点偷跑流量

某一天&#xff0c;校园网账号登不上了&#xff0c;就给电脑连上了手机热点继续学习TensorFlow&#xff0c;hhhhh。 但是没过多久手机热点自动关了&#xff08;因为设置的单次流量上限&#xff09;&#xff0c;再仔细一看&#xff0c;手机的流量显示每秒1-2MB/S在耗费着流量&am…

Android之——流量管理程序示例

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47680811目前&#xff0c;市面上有很多管理手机流量的软件&#xff0c;可以让用户实时获取到自己手机中当前消耗了多少流量&#xff0c;手机中每个应用程序消耗了多少手机流量&#xff0c;那么这些功能Androi…

超级棒的手机流量管理软件,节约流量有技巧

&#xfeff;&#xfeff; 过年回家了&#xff0c;手机卡异地漫游&#xff0c;流量超了7兆多&#xff0c;中国联通是大爷&#xff0c;扣我70多块钱&#xff0c;我都崩溃了。果断找了一款管理流量的软件&#xff0c;可以查流量还有多少&#xff0c;查杀隐蔽流量&#xff0c;功能…

js包管理yarn与npm,yarn安装,yarn 不是内部或外部命令

目录 yarn与npm 优势 用法区别 安装yarn 报错 yarn 不是内部或外部命令 运行代码&#xff08;yarn dev&#xff09; yarn与npm yarn由Facebook为解决npm的一些问题而创建的 优势 快速 本地缓存并行下载 - Yarn并行下载&#xff0c;还可以直接从硬盘缓存中读取包&…