android 應(yīng)用流量統(tǒng)計 NetworkStatsManager api 的使用及demo

先上完成效果

流量監(jiān)控.gif

編譯 環(huán)境 及工具

AS4.0 jdk1.8
測試的android系統(tǒng) 6.0 以上 在7.1安卓板 和 手機 android13 上測試了可以使用 。只寫了移動流量的展示

NetworkStatsManager 的api 說明

1. NetworkStatsManager類

網(wǎng)絡(luò)數(shù)據(jù)管理類 Android 6.0后推出的
提供對網(wǎng)絡(luò)使用歷史和統(tǒng)計數(shù)據(jù)的訪問,分為Summary queries(摘要查詢)和 History queries(歷史查詢)
根據(jù)實際場景 個人建議盡量使用Summary queries

2.我使用的幾個api如下

2.1.API方法


 
    查詢網(wǎng)絡(luò)使用統(tǒng)計摘要。(查詢多個應(yīng)用流量統(tǒng)計) 會返回多個桶 需要循環(huán)遍歷 在根據(jù)uid 的到每一個的實時流量
    querySummary(int networkType, String subscriberId, long startTime, long endTime)
    
    查詢網(wǎng)絡(luò)使用統(tǒng)計摘要。結(jié)果是整個設(shè)備的匯總數(shù)據(jù)使用情況。結(jié)果是隨著時間、狀態(tài)、uid、標(biāo)簽、計量和漫游聚合的單個存儲桶
    querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime)
    
 

2.2.API方法中的參數(shù)說明


1.networkType 查詢網(wǎng)絡(luò)類型 (ConnectivityManager.TYPE_WIFI,ConnectivityManager.TYPE_MOBILE)
2.subscriberId 設(shè)備唯一id(android 10及以后設(shè)備 獲取不了,可不傳)
3.startTime 查詢指定時間段 開始時間戳
4.endTime 查詢指定時間段 結(jié)束時間戳
5.uid 查詢設(shè)備的Uid    這個我用的是在方法里判斷了
 

3. api方法的使用

3.1.querySummaryForDevice的使用 整個設(shè)備的匯總數(shù)據(jù)使用情況

  /**
     * 獲取 所有移動使用流量信息
     *
     * @param context       上下文
     * @param isDayAndMonth 是否是當(dāng)天還是當(dāng)月
     * @return 返回 當(dāng)天 還是當(dāng)月的流量信息
     */
    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 的使用 (查詢多個應(yīng)用流量統(tǒng)計)

我使用這個是查詢每一個應(yīng)用的的實時流量情況

記得使用過后 記得釋放 網(wǎng)絡(luò)統(tǒng)計信息 networkStats.close() 記得判空 我開始沒有釋放這個,報系統(tǒng)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 是否是當(dāng)天還是當(dāng)月
     * @return 返回 當(dāng)天 還是當(dāng)月的流量信息
     */
    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;
    }

    /**
     * 獲取所有應(yīng)用一天使用的移動流量信息
     *
     * @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;
    }

    /**
     * 獲取今日 或者今月的 應(yīng)用 的實時流量使用情況
     *
     * @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 即可
     * 需要權(quán)限
     * <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     *
     * @param context     上下文
     * @param networkType 網(wǎng)絡(luò)類型
     * @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的準(zhǔn)備工作

4.1 需要的相關(guān)權(quán)限及權(quán)限的申請

大家先在 AndroidManifest.xml 添加如下權(quán)限內(nèi)


  <!--Android 11獲取應(yīng)用列表 權(quán)限-->
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
    <!--    適配安卓12&11獲取當(dāng)前已安裝的所有應(yīng)用列表-->

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

    <!--包使用情況統(tǒng)計-->
    <uses-permission
        android:name="android.permission.PACKAGE_USAGE_STATS"
        tools:ignore="ProtectedPermissions" />

    <!--讀取手機狀態(tài)   這個是在getSubscriberId()用到的 android10后就可刪除,因為不讓獲取了 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

4.2 權(quán)限的申請

1.獲取使用情況統(tǒng)計權(quán)限

  // 打開 "有權(quán)查看使用情況的應(yīng)用"頁面
    private void requestReadNetworkStats() {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 經(jīng)過測試,只有在 Android 10 及以上加包名才有效果
            // 如果在 Android 10 以下加包名會導(dǎo)致無法跳轉(zhuǎn)
            intent.setData(Uri.parse("package:" + getPackageName()));
        }
        startActivity(intent);
    }

   private boolean hasPermissionToReadNetworkStats() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            Log.i("流量-", "==當(dāng)前版本小于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.讀取應(yīng)用列表權(quán)限 下面這倆個選擇一個就可以   點擊應(yīng)用排行列表的時候需要手動授權(quán)

<!-- Android 11獲取應(yīng)用列表 權(quán)限&ndash;&gt;-->
    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />


    <!--    適配安卓12&11獲取當(dāng)前已安裝的所有應(yīng)用列表-->
    <queries>
        <intent>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent>
    </queries>

4.3 獲取手機應(yīng)用列表 下面選擇一個使用即可

1.獲取擁有internet權(quán)限的應(yīng)用列表
   /**
     * 獲取擁有internet權(quán)限的應(yīng)用列表
     *
     * @return
     */
    public List<TrafficInfo> getInternetTrafficInfos() {
        List<TrafficInfo> trafficInfos = new ArrayList<TrafficInfo>();
        //獲取手機中安裝的并且具有權(quán)限的應(yīng)用  PackageManager.GET_UNINSTALLED_PACKAGES |
        List<PackageInfo> installedPackages = pm.getInstalledPackages(
                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);
        for (PackageInfo info : installedPackages) {
            //獲取權(quán)限數(shù)組
            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.獲取所有 的應(yīng)用列表
 /**
     * 獲取所有 的應(yīng)用列表
     *
     * @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轉(zhuǎn)換成Bitmap

這個是展示App流量排行時 需要把獲取到的icon 轉(zhuǎn)成bitmap 進(jìn)行顯示

 /**
     * 將Drawable轉(zhuǎn)成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;

    /**
     * 格式化數(shù)據(jù)
     *
     * @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 "超出統(tǒng)計范圍";
        }
    }
}


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


    /**
     * 獲得當(dāng)前時間的<code java.util.Date</code 對象
     *
     * @return
     */
    public static Date now() {
        return new Date();
    }
    /**
     * 獲取當(dāng)天的零點時間
     */
    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();
    }

    /**
     * 獲得當(dāng)前月的第一天
     * <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();
    }

    /**
     * 獲得當(dāng)前月的第一天
     * <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();
    }


    /**
     * 獲得當(dāng)前月的第一天到當(dāng)前時間的時間戳集合
     * <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;
    }


    /**
     * 獲得天數(shù)差
     *
     * @param begin 開始
     * @param end   結(jié)束
     * @return 天數(shù)
     */
    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的結(jié)構(gòu)展示及具體實現(xiàn)

5.1 結(jié)構(gòu)如下圖所示

流量監(jiān)控項目代碼類圖.png

5.2 功能的實現(xiàn)

5.2.1. TrafficActivity 流量監(jiān)控首頁 進(jìn)行整個流量及每一天的總流量展示

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;

/**
 * 流量監(jiān)控首頁 進(jìn)行整個流量及每一天的總流量展示
 */
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;//網(wǎng)絡(luò)數(shù)據(jù)管理
    NetworkStatsHelper helper = null;//網(wǎng)絡(luò)數(shù)據(jù)助手
    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("流量-", "==有權(quán)查看使用情況的應(yīng)用的權(quán)限未授權(quán)==");
            return;
        }
        Log.i("流量-", "==有權(quán)查看使用情況的應(yīng)用的權(quán)限授權(quán)成功==");
        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("當(dāng)月已用總流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getTotalData())));
        trafficDayAllTv.setText(String.format("當(dāng)天已用總流量\n%s", TrafficFormat.formatByte(
                dayTraffic.getTotalData())));


        trafficMonthDownallTv.setText(String.format("當(dāng)月下載流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getRxBytes())));
        trafficMonthUpallTv.setText(String.format("當(dāng)月上傳流量\n%s", TrafficFormat.formatByte(
                monthTraffic.getTxBytes())));


        trafficDayDownallTv.setText(String.format("當(dāng)天下載流量\n%s", TrafficFormat.formatByte(
                dayTraffic.getRxBytes())));
        trafficDayUpallTv.setText(String.format("當(dāng)天上傳流量\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, "點擊了應(yīng)用排行", Toast.LENGTH_SHORT).show();
        startActivity(new Intent(TrafficActivity.this,
                TrafficAppActivity.class));

    }

    // 打開 "有權(quán)查看使用情況的應(yīng)用"頁面
    private void requestReadNetworkStats() {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 經(jīng)過測試,只有在 Android 10 及以上加包名才有效果
            // 如果在 Android 10 以下加包名會導(dǎo)致無法跳轉(zhuǎn)
            intent.setData(Uri.parse("package:" + getPackageName()));
        }
        startActivity(intent);
    }

    /**
     * 檢查是否有有權(quán)查看使用情況的應(yīng)用的權(quán)限
     *
     * @return true false
     */
    private boolean hasPermissionToReadNetworkStats() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            Log.i("流量-", "==當(dāng)前版本小于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;

    }

    /**
     * 查詢應(yīng)用列表權(quán)限進(jìn)行跳頁
     */
    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 應(yīng)用流量排行APP頁 進(jìn)行今日和今月列表切換 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;


/**
 * 應(yīng)用流量排行APP頁   進(jìn)行今日和今月列表切換  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的數(shù)量=" + 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. 具體布局及整體實現(xiàn)請看開頭的gif 或者源碼 自行實現(xiàn)

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.完結(jié)

撒花.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容