android 应用流量统计 NetworkStatsManager api 的使用及demo

先上完成效果

流量监控.gif

编译 环境 及工具

AS4.0 jdk1.8
测试的android系统 6.0 以上 在7.1安卓板 和 手机 android13 上测试了可以使用 。只写了移动流量的展示

NetworkStatsManager 的api 说明

1. NetworkStatsManager类

网络数据管理类 Android 6.0后推出的
提供对网络使用历史和统计数据的访问,分为Summary queries(摘要查询)和 History queries(历史查询)
根据实际场景 个人建议尽量使用Summary queries

2.我使用的几个api如下

2.1.API方法


 
    查询网络使用统计摘要。(查询多个应用流量统计) 会返回多个桶 需要循环遍历 在根据uid 的到每一个的实时流量
    querySummary(int networkType, String subscriberId, long startTime, long endTime)
    
    查询网络使用统计摘要。结果是整个设备的汇总数据使用情况。结果是随着时间、状态、uid、标签、计量和漫游聚合的单个存储桶
    querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime)
    
 

2.2.API方法中的参数说明


1.networkType 查询网络类型 (ConnectivityManager.TYPE_WIFI,ConnectivityManager.TYPE_MOBILE)
2.subscriberId 设备唯一id(android 10及以后设备 获取不了,可不传)
3.startTime 查询指定时间段 开始时间戳
4.endTime 查询指定时间段 结束时间戳
5.uid 查询设备的Uid    这个我用的是在方法里判断了
 

3. api方法的使用

3.1.querySummaryForDevice的使用 整个设备的汇总数据使用情况

  /**
     * 获取 所有移动使用流量信息
     *
     * @param context       上下文
     * @param isDayAndMonth 是否是当天还是当月
     * @return 返回 当天 还是当月的流量信息
     */
    public TrafficBean getAllDay_MonthMobileInfo(Context context, boolean isDayAndMonth) {
        TrafficBean trafficBean = new TrafficBean();
        NetworkStats.Bucket bucket;
        try {
            bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE,
                    getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
                    isDayAndMonth ? getTimesmorning() : getTimesMonthmorning(),
                    System.currentTimeMillis());
        } catch (RemoteException e) {
            return trafficBean;

        }

        trafficBean.setRxBytes(bucket.getRxBytes());
        trafficBean.setTxBytes(bucket.getTxBytes());
        trafficBean.setTotalData(bucket.getTxBytes() + bucket.getRxBytes());


        return trafficBean;
    }

3.2.querySummary 的使用 (查询多个应用流量统计)

我使用这个是查询每一个应用的的实时流量情况

记得使用过后 记得释放 网络统计信息 networkStats.close() 记得判空 我开始没有释放这个,报系统system 异常 但是不影响使用

    /**
     * 获取今日 或者今月的实时流量使用情况
     *
     * @param context       上下文
     * @param isDayAndMonth 是否是今天还是今月
     * @return 获取今日 或者今月的流量使用情况
     */
    public TrafficBean getSummaryTrafficMobile(Context context, boolean isDayAndMonth) {
        TrafficBean trafficBean = new TrafficBean();
        trafficBean.setUid(packageUid + "");
        NetworkStats networkStats = null;

        try {
            networkStats = networkStatsManager.querySummary(
                    ConnectivityManager.TYPE_MOBILE,
                    getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
                    isDayAndMonth ? getTimesmorning() : getTimesMonthmorning(),
                    System.currentTimeMillis());


            long mobileTraffic = 0;//
            long mobileRx = 0;
            long mobileTx = 0;
            NetworkStats.Bucket bucket = new NetworkStats.Bucket();
            do {
                networkStats.getNextBucket(bucket);
                int summaryUid = bucket.getUid();
                if (packageUid == summaryUid) {

                    mobileTx += bucket.getTxBytes();
                    mobileRx += bucket.getRxBytes();
                }
            } while (networkStats.hasNextBucket());
            mobileTraffic = mobileRx + mobileTx;

            trafficBean.setTxBytes(mobileTx);
            trafficBean.setRxBytes(mobileRx);
            trafficBean.setTotalData(mobileTraffic);


        } catch (RemoteException e) {
            e.printStackTrace();
        } finally {
            if (networkStats != null) {
                networkStats.close();
            }
        }
        return trafficBean;
    }

3.3完整代码NetworkStatsHelper


import android.annotation.SuppressLint;
import android.app.usage.NetworkStats;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.RemoteException;
import android.telephony.TelephonyManager;

import androidx.annotation.RequiresApi;

import com.tjf.traffic.bean.TrafficBean;


/**
 * @author: tjf
 * @date: 2022-12-10
 * @desc: NetworkStatsHelper 流量查询辅助类
 *
 * <p> 使用方式
 * * NetworkStatsManager networkStatsManager = (NetworkStatsManager) getSystemService(NETWORK_STATS_SERVICE);
 * * NetworkStatsHelper helper = new NetworkStatsHelper(networkStatsManager);
 * </p>
 */
@RequiresApi(api = Build.VERSION_CODES.M)
public class NetworkStatsHelper {

    NetworkStatsManager networkStatsManager;
    int packageUid;

    public void setPackageUid(int packageUid) {
        this.packageUid = packageUid;
    }

    public NetworkStatsHelper(NetworkStatsManager networkStatsManager) {
        this.networkStatsManager = networkStatsManager;
    }

    public NetworkStatsHelper(NetworkStatsManager networkStatsManager, int packageUid) {
        this.networkStatsManager = networkStatsManager;
        this.packageUid = packageUid;
    }


    /**
     * 获取 所有移动使用流量信息
     *
     * @param context       上下文
     * @param isDayAndMonth 是否是当天还是当月
     * @return 返回 当天 还是当月的流量信息
     */
    public TrafficBean getAllDay_MonthMobileInfo(Context context, boolean isDayAndMonth) {
        TrafficBean trafficBean = new TrafficBean();
        NetworkStats.Bucket bucket;
        try {
            bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE,
                    getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
                    isDayAndMonth ? DateUtil.getTimesmorning() :DateUtil. getTimesMonthmorning(),
                    System.currentTimeMillis());
        } catch (RemoteException e) {
            return trafficBean;

        }

        trafficBean.setRxBytes(bucket.getRxBytes());
        trafficBean.setTxBytes(bucket.getTxBytes());
        trafficBean.setTotalData(bucket.getTxBytes() + bucket.getRxBytes());


        return trafficBean;
    }

    /**
     * 获取所有应用一天使用的移动流量信息
     *
     * @param context   上下文
     * @param startTime 开始时间
     * @return 流量信息
     */
    public TrafficBean getOneDayMobileInfo(Context context, long startTime) {
        TrafficBean trafficBean = new TrafficBean();
        NetworkStats.Bucket bucket;
        try {
            bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE,
                    getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
                    startTime,
                    startTime + 86400000
            );


            trafficBean.setRxBytes(bucket.getRxBytes());
            trafficBean.setTxBytes(bucket.getTxBytes());
            trafficBean.setTotalData(bucket.getTxBytes() + bucket.getRxBytes());

        } catch (RemoteException e) {
            return trafficBean;

        }
        return trafficBean;
    }

    /**
     * 获取今日 或者今月的 应用 的实时流量使用情况
     *
     * @param context       上下文
     * @param isDayAndMonth 是否是今天还是今月
     * @return 获取今日 或者今月的流量使用情况
     */
    public TrafficBean getSummaryTrafficMobile(Context context, boolean isDayAndMonth) {
        TrafficBean trafficBean = new TrafficBean();
        trafficBean.setUid(packageUid + "");
        NetworkStats networkStats = null;

        try {
            networkStats = networkStatsManager.querySummary(
                    ConnectivityManager.TYPE_MOBILE,
                    getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
                    isDayAndMonth ? DateUtil.getTimesmorning() :DateUtil. getTimesMonthmorning(),
                    System.currentTimeMillis());


            long mobileTraffic = 0;//
            long mobileRx = 0;
            long mobileTx = 0;
            NetworkStats.Bucket bucket = new NetworkStats.Bucket();
            do {
                networkStats.getNextBucket(bucket);
                int summaryUid = bucket.getUid();
                if (packageUid == summaryUid) {

                    mobileTx += bucket.getTxBytes();
                    mobileRx += bucket.getRxBytes();
                }
            } while (networkStats.hasNextBucket());
            mobileTraffic = mobileRx + mobileTx;

            trafficBean.setTxBytes(mobileTx);
            trafficBean.setRxBytes(mobileRx);
            trafficBean.setTotalData(mobileTraffic);


        } catch (RemoteException e) {
            e.printStackTrace();
        } finally {
            if (networkStats != null) {
                networkStats.close();
            }
        }


        return trafficBean;
    }

    /**
     * 获取用户id android 10 以后获取不了 传null 即可
     * 需要权限
     * <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     *
     * @param context     上下文
     * @param networkType 网络类型
     * @return null
     */
    @SuppressLint("MissingPermission")
    private String getSubscriberId(Context context, int networkType) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return null;
        }

        if (ConnectivityManager.TYPE_MOBILE == networkType) {
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            return tm.getSubscriberId();
        }
        return null;
    }


}
 

4 测试demo的准备工作

4.1 需要的相关权限及权限的申请

大家先在 AndroidManifest.xml 添加如下权限内


  <!--Android 11获取应用列表 权限-->
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
    <!--    适配安卓12&11获取当前已安装的所有应用列表-->

    <queries>
        <intent>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent>
    </queries>

    <!--包使用情况统计-->
    <uses-permission
        android:name="android.permission.PACKAGE_USAGE_STATS"
        tools:ignore="ProtectedPermissions" />

    <!--读取手机状态   这个是在getSubscriberId()用到的 android10后就可删除,因为不让获取了 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

4.2 权限的申请

1.获取使用情况统计权限

  // 打开 "有权查看使用情况的应用"页面
    private void requestReadNetworkStats() {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 经过测试,只有在 Android 10 及以上加包名才有效果
            // 如果在 Android 10 以下加包名会导致无法跳转
            intent.setData(Uri.parse("package:" + getPackageName()));
        }
        startActivity(intent);
    }

   private boolean hasPermissionToReadNetworkStats() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            Log.i("流量-", "==当前版本小于23==");
            return true;
        }

        final AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
        int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
                          Process.myUid(), getPackageName());
        if (mode == AppOpsManager.MODE_ALLOWED) {
            return true;
        }
        requestReadNetworkStats();
        return false;
    }

2.读取应用列表权限 下面这俩个选择一个就可以   点击应用排行列表的时候需要手动授权

<!-- Android 11获取应用列表 权限&ndash;&gt;-->
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />


    <!--    适配安卓12&11获取当前已安装的所有应用列表-->
    <queries>
        <intent>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent>
    </queries>

4.3 获取手机应用列表 下面选择一个使用即可

1.获取拥有internet权限的应用列表
   /**
     * 获取拥有internet权限的应用列表
     *
     * @return
     */
    public List<TrafficInfo> getInternetTrafficInfos() {
        List<TrafficInfo> trafficInfos = new ArrayList<TrafficInfo>();
        //获取手机中安装的并且具有权限的应用  PackageManager.GET_UNINSTALLED_PACKAGES |
        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;
    }


2.获取所有 的应用列表
 /**
     * 获取所有 的应用列表
     *
     * @return
     */
    public List<TrafficInfo> getInstalledApplications() {
        List<TrafficInfo> trafficInfos = new ArrayList<TrafficInfo>();

        List<ApplicationInfo> installedPackages = pm.getInstalledApplications(
                0);
        for (ApplicationInfo applicationInfo : installedPackages) {

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

4.4 Drawable转换成Bitmap

这个是展示App流量排行时 需要把获取到的icon 转成bitmap 进行显示

 /**
     * 将Drawable转成Bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap;
        try {
            bitmap = Bitmap.createBitmap(
                    drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight(),
                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                            : Bitmap.Config.RGB_565);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight());
            drawable.draw(canvas);
        } catch (Exception e) {
            bitmap = null;
        }
        return bitmap;
    }

4.5 流量文本格式化工具类

/**
 * @author: tjf
 * @desc: 流量文本格式化工具类
 */
public class TrafficFormat {
    //定义TB的计算常量
    private static final double TB = 1024f * 1024f * 1024f * 1024f;
    //定义GB的计算常量
    private static final double GB = 1024f * 1024f * 1024f;
    //定义MB的计算常量
    private static final double MB = 1024f * 1024f;
    //定义KB的计算常量
    private static final double KB = 1024f;

    /**
     * 格式化数据
     *
     * @param data
     * @return
     */
    public static String formatByte(long data) {

        DecimalFormat format = new DecimalFormat("####.##");
        if (data < KB) {
            return data + "B";
        } else if (data < MB) {
            return format.format(data / KB) + "KB";
        } else if (data < GB) {
            return format.format(data / MB) + "MB";
        } else if (data < TB) {
            return format.format(data / GB) + "GB";
        } else {
            return "超出统计范围";
        }
    }
}


4.6 日期工具类

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * @author: tjf
 * @desc: 日期操作工具类.
 */
public class DateUtil {

    /**
     * 格式到天
     *
     * @param time
     * @return
     */
    public static String getDay(long time) {
        return new SimpleDateFormat("yyyy-MM-dd").format(time);
    }


    /**
     * 获得当前时间的<code java.util.Date</code 对象
     *
     * @return
     */
    public static Date now() {
        return new Date();
    }
    /**
     * 获取当天的零点时间
     */
    public static long getTimesmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return (cal.getTimeInMillis());
    }


    /**
     * 获得本月第一天0点时间
     */
    public static long getTimesMonthmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 1); // M月置1
        cal.set(Calendar.HOUR_OF_DAY, 0);// H置零
        cal.set(Calendar.MINUTE, 0);// m置零
        cal.set(Calendar.SECOND, 0);// s置零
        cal.set(Calendar.MILLISECOND, 0);// S置零

        return cal.getTimeInMillis();
    }

    /**
     * 获得当前月的第一天
     * <p>
     * HH:mm:ss SS为零
     *
     * @return
     */
    public static Date firstDayOfMonthData() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, 1); // M月置1
        cal.set(Calendar.HOUR_OF_DAY, 0);// H置零
        cal.set(Calendar.MINUTE, 0);// m置零
        cal.set(Calendar.SECOND, 0);// s置零
        cal.set(Calendar.MILLISECOND, 0);// S置零
        return cal.getTime();
    }

    /**
     * 获得当前月的第一天
     * <p>
     * HH:mm:ss SS为零
     *
     *
     */
    public static long firstDayOfMonth(int DAY_OF_MONTH) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, DAY_OF_MONTH); // M月置1
        cal.set(Calendar.HOUR_OF_DAY, 0);// H置零
        cal.set(Calendar.MINUTE, 0);// m置零
        cal.set(Calendar.SECOND, 0);// s置零
        cal.set(Calendar.MILLISECOND, 0);// S置零
        return cal.getTimeInMillis();
    }


    /**
     * 获得当前月的第一天到当前时间的时间戳集合
     * <p>
     * HH:mm:ss SS为零
     *
     *
     */
    public static List<Long> getListDayOfMonth() {
        List<Long> dayOfMonth = new ArrayList<>();
        long days = getDayDiff(firstDayOfMonthData(), now());
        for (int i = 1; i <= days; i++) {
            long day = firstDayOfMonth(i);
            dayOfMonth.add(day);
        }
        Collections.sort(dayOfMonth, new Comparator<Long>() {
            @Override
            public int compare(Long o1, Long o2) {
                return (int) (o2 - o1);
            }
        });
        return dayOfMonth;
    }


    /**
     * 获得天数差
     *
     * @param begin 开始
     * @param end   结束
     * @return 天数
     */
    public static long getDayDiff(Date begin, Date end) {
        long day = 1;
        if (end.getTime() < begin.getTime()) {
            day = -1;
        } else if (end.getTime() == begin.getTime()) {
            day = 1;
        } else {
            day += (end.getTime() - begin.getTime()) / (24 * 60 * 60 * 1000);
        }
        return day;
    }
}

5.主App的结构展示及具体实现

5.1 结构如下图所示

流量监控项目代码类图.png

5.2 功能的实现

5.2.1. TrafficActivity 流量监控首页 进行整个流量及每一天的总流量展示

import android.app.AppOpsManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.tjf.traffic.adapter.TrafficDateAdapter;
import com.tjf.traffic.bean.TrafficDayInfo;
import com.tjf.traffic.utils.DateUtil;
import com.tjf.traffic.utils.NetworkStatsHelper;
import com.tjf.traffic.bean.TrafficBean;
import com.tjf.traffic.utils.TrafficFormat;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * 流量监控首页 进行整个流量及每一天的总流量展示
 */
public class TrafficActivity extends AppCompatActivity {

    @BindView(R.id.traffic_list_rev)
    RecyclerView trafficListRev;


    @BindView(R.id.traffic_month_all_tv)
    TextView trafficMonthAllTv;
    @BindView(R.id.traffic_day_all_tv)
    TextView trafficDayAllTv;
    @BindView(R.id.traffic_month_downall_tv)
    TextView trafficMonthDownallTv;
    @BindView(R.id.traffic_month_upall_tv)
    TextView trafficMonthUpallTv;
    @BindView(R.id.traffic_day_downall_tv)
    TextView trafficDayDownallTv;
    @BindView(R.id.traffic_day_upall_tv)
    TextView trafficDayUpallTv;


    @BindView(R.id.total_traffic_tv)
    TextView totalTrafficTv;
    @BindView(R.id.total_up_traffic_tv)
    TextView totalUpTrafficTv;
    @BindView(R.id.total_down_traffic_tv)
    TextView totalDownTrafficTv;
    @BindView(R.id.traffic_app_sort_lly)
    LinearLayout trafficAppSortLly;
    @BindView(R.id.traffic_goback)
    ImageView trafficGoback;


    TrafficDateAdapter trafficDateAdapter;//每天流量展示适配器
    NetworkStatsManager networkStatsManager = null;//网络数据管理
    NetworkStatsHelper helper = null;//网络数据助手
    List<TrafficDayInfo> dateTraficlist = new ArrayList<>();//每天的流量集合

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_traffic);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            networkStatsManager = (NetworkStatsManager) getSystemService(NETWORK_STATS_SERVICE);
        }
        helper = new NetworkStatsHelper(networkStatsManager);

        trafficAppSortLly.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkUserAppListPerMission();
            }
        });
        trafficGoback.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onResume() {
        super.onResume();
        if (!hasPermissionToReadNetworkStats()) {
            Log.i("流量-", "==有权查看使用情况的应用的权限未授权==");
            return;
        }
        Log.i("流量-", "==有权查看使用情况的应用的权限授权成功==");
        setTrafficList();
    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    public void setTrafficList() {

        TrafficBean monthTraffic = helper.getAllDay_MonthMobileInfo(this, false);
        TrafficBean dayTraffic = helper.getAllDay_MonthMobileInfo(this, true);
        trafficMonthAllTv.setText(String.format("当月已用总流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getTotalData())));
        trafficDayAllTv.setText(String.format("当天已用总流量\n%s", TrafficFormat.formatByte(
                dayTraffic.getTotalData())));


        trafficMonthDownallTv.setText(String.format("当月下载流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getRxBytes())));
        trafficMonthUpallTv.setText(String.format("当月上传流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getTxBytes())));


        trafficDayDownallTv.setText(String.format("当天下载流量\n%s", TrafficFormat.formatByte(
                dayTraffic.getRxBytes())));
        trafficDayUpallTv.setText(String.format("当天上传流量\n%s", TrafficFormat.formatByte(
                dayTraffic.getTxBytes())));

        getDateAndMonthInfo();
        trafficDateAdapter = new TrafficDateAdapter(this,
                dateTraficlist, R.layout.traffic_date_item);
        trafficListRev.setLayoutManager(new LinearLayoutManager(this));
        trafficListRev.setAdapter(trafficDateAdapter);

    }


    public void startAppListPage() {
        Toast.makeText(this, "点击了应用排行", Toast.LENGTH_SHORT).show();
        startActivity(new Intent(TrafficActivity.this,
                TrafficAppActivity.class));

    }

    // 打开 "有权查看使用情况的应用"页面
    private void requestReadNetworkStats() {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 经过测试,只有在 Android 10 及以上加包名才有效果
            // 如果在 Android 10 以下加包名会导致无法跳转
            intent.setData(Uri.parse("package:" + getPackageName()));
        }
        startActivity(intent);
    }

    /**
     * 检查是否有有权查看使用情况的应用的权限
     *
     * @return true false
     */
    private boolean hasPermissionToReadNetworkStats() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            Log.i("流量-", "==当前版本小于23==");
            return true;
        }
        final AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
        int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), getPackageName());
        if (mode == AppOpsManager.MODE_ALLOWED) {
            return true;
        }
        requestReadNetworkStats();
        return false;

    }

    /**
     * 查询应用列表权限进行跳页
     */
    public void checkUserAppListPerMission() {
        startAppListPage();
    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    public void getDateAndMonthInfo() {
        dateTraficlist.clear();

        long totalTx = 0;
        long totalRx = 0;
        long totalTraffic;

        List<Long> dateList = DateUtil.getListDayOfMonth();
        for (Long datelong : dateList) {
            TrafficBean oneTraffic = helper.getOneDayMobileInfo(this, datelong);

            TrafficDayInfo usageDate = new TrafficDayInfo();
            usageDate.setDateDay(datelong);
            usageDate.setDateDayStr(DateUtil.getDay(datelong));


            usageDate.setTotalRxBytes(TrafficFormat.formatByte(oneTraffic.getRxBytes()));
            usageDate.setTotalTxBytes(TrafficFormat.formatByte(oneTraffic.getTxBytes()));
            usageDate.setTotalTraffic(TrafficFormat.formatByte(oneTraffic.getTotalData()));
            dateTraficlist.add(usageDate);
            totalTx += oneTraffic.getTxBytes();
            totalRx += oneTraffic.getRxBytes();
        }
        totalTraffic = totalRx + totalTx;

        setTotalTraffic(TrafficFormat.formatByte(totalTraffic),
                TrafficFormat.formatByte(totalTx), TrafficFormat.formatByte(totalRx));
        Log.i("流量-", "==流量的汇总==\n"
                + TrafficFormat.formatByte(totalTraffic)
                + "\n上传流量合计:" +
                TrafficFormat.formatByte(totalTx)
                + "\n下载流量合计:" + TrafficFormat.formatByte(totalRx));
    }

    /**
     * 流量合计
     */
    public void setTotalTraffic(String totalTraffic, String upTraffic, String downTraffic) {
        totalTrafficTv.setText(String.format("总流量:%s", totalTraffic));
        totalUpTrafficTv.setText(String.format("上传总流量:%s", upTraffic));
        totalDownTrafficTv.setText(String.format("下载总流量:%s", downTraffic));
    }
}

5.2.2. TrafficAppActivity 应用流量排行APP页 进行今日和今月列表切换 App流量的排行展示

import android.app.usage.NetworkStatsManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.tjf.traffic.adapter.TrafficAppAdapter;
import com.tjf.traffic.bean.TrafficInfo;
import com.tjf.traffic.utils.NetworkStatsHelper;
import com.tjf.traffic.bean.TrafficBean;
import com.tjf.traffic.utils.TrafficFormat;
import com.tjf.traffic.utils.TrafficManagerApp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;


/**
 * 应用流量排行APP页   进行今日和今月列表切换  App流量的排行展示
 */
public class TrafficAppActivity extends AppCompatActivity {

    @BindView(R.id.traffic_list_rev)
    RecyclerView trafficListRev;
    @BindView(R.id.traffic_day_month_tv)
    TextView trafficDayMonthTv;
    @BindView(R.id.total_traffic_tv)
    TextView totalTrafficTv;
    @BindView(R.id.total_up_traffic_tv)
    TextView totalUpTrafficTv;
    @BindView(R.id.total_down_traffic_tv)
    TextView totalDownTrafficTv;
    @BindView(R.id.traffic_goback)
    ImageView trafficGoback;

    TrafficAppAdapter trafficAppAdapter;
    NetworkStatsManager networkStatsManager = null;
    NetworkStatsHelper helper;

    List<TrafficInfo> trafficApplist = new ArrayList<>();
    TrafficManagerApp trafficManagerApp;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_traffic_app);
        ButterKnife.bind(this);
        trafficManagerApp = new TrafficManagerApp(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            networkStatsManager = (NetworkStatsManager) getSystemService(NETWORK_STATS_SERVICE);
        }
        helper = new NetworkStatsHelper(networkStatsManager);
        getDayAndMonthInfo(true);
        trafficAppAdapter = new TrafficAppAdapter(this,
                trafficApplist, R.layout.traffic_app_item);
        trafficListRev.setLayoutManager(new LinearLayoutManager(this));
        trafficListRev.setAdapter(trafficAppAdapter);


        trafficDayMonthTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (trafficDayMonthTv.getText().toString().equals("今日")) {
                    trafficDayMonthTv.setText("今月");
                    getDayAndMonthInfo(false);
                } else if (trafficDayMonthTv.getText().toString().equals("今月")) {
                    trafficDayMonthTv.setText("今日");
                    getDayAndMonthInfo(true);
                }
                Toast.makeText(TrafficAppActivity.this,
                        "点击了" + trafficDayMonthTv.getText().toString(), Toast.LENGTH_SHORT).show();
                if (trafficAppAdapter != null) {
                    trafficAppAdapter.notifyDataSetChanged();
                }
            }
        });
        trafficGoback.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    public void getDayAndMonthInfo(boolean isDayAndMonth) {
        trafficApplist.clear();
        trafficApplist.addAll(trafficManagerApp.getInternetTrafficInfos());
        long totalTx = 0;
        long totalRx = 0;
        long totalTraffic;
        for (TrafficInfo trafficInfo : trafficApplist) {
            helper.setPackageUid(trafficInfo.getUid());
            TrafficBean trafficBean = helper.getSummaryTrafficMobile(this, isDayAndMonth);
            trafficInfo.setTraffic(TrafficFormat.formatByte(trafficBean.getTotalData()));
            trafficInfo.setMobleTotalData(trafficBean.getTotalData());
            trafficInfo.setMobleRxBytes(trafficBean.getRxBytes());
            trafficInfo.setMobleTxBytes(trafficBean.getTxBytes());
            totalTx += trafficBean.getTxBytes();
            totalRx += trafficBean.getRxBytes();
        }
        totalTraffic = totalRx + totalTx;

        Log.i("流量-", "==流量的汇总==\n"
                + TrafficFormat.formatByte(totalTraffic)
                + "\n上传流量合计:" +
                TrafficFormat.formatByte(totalTx)
                + "\n下载流量合计:" + TrafficFormat.formatByte(totalRx));

        setTotalTraffic(TrafficFormat.formatByte(totalTraffic),
                TrafficFormat.formatByte(totalTx), TrafficFormat.formatByte(totalRx));

        for (int i = trafficApplist.size() - 1; i >= 0; i--) {
            TrafficInfo trafficInfo = trafficApplist.get(i);
            if (trafficInfo.getTraffic().startsWith("0")) {
                trafficApplist.remove(i);
            }
        }
        Log.i("流量-", "过滤后的app的数量=" + trafficApplist.size());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Collections.sort(trafficApplist, new Comparator<TrafficInfo>() {
                @Override
                public int compare(TrafficInfo o1, TrafficInfo o2) {
                    //流量最大值排列
                    int max = (int) (o2.getMobleTotalData() - o1.getMobleTotalData());
                    return max;
                }
            });
        }
    }


    /**
     * 流量合计
     */
    public void setTotalTraffic(String totalTraffic, String upTraffic, String downTraffic) {
        totalTrafficTv.setText(String.format("总流量:%s", totalTraffic));

        totalUpTrafficTv.setText(String.format("上传总流量:%s", upTraffic));

        totalDownTrafficTv.setText(String.format("下载总流量:%s", downTraffic));

    }

5.2.3. 具体布局及整体实现请看开头的gif 或者源码 自行实现

demo项目地址 https://toscode.gitee.com/code_tjf/traffic-demo

6.下面是参考的博客地址:

https://blog.csdn.net/Rookie_or_beginner/article/details/123376004?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123376004-blog-8440160.pc_relevant_multi_platform_whitelistv4&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123376004-blog-8440160.pc_relevant_multi_platform_whitelistv4&utm_relevant_index=1

7.完结

撒花.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容