安卓 流量相关功能实现记录

1. 静态声明权限,在AndroidManifest.xml中申明

    <uses-permission xmlns:tools="http://schemas.android.com/tools"android:name="android.permission.PACKAGE_USAGE_STATS"tools:ignore="ProtectedPermissions" />

2.判断并动态申请 [使用情况] 权限

//是否拥有权限    
private fun hasPermission(): Boolean {return XXPermissions.isGranted(requireContext(), Manifest.permission.PACKAGE_USAGE_STATS)}//申请权限的方法
private fun startSettings() {val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)if (intent.resolveActivity(requireContext().packageManager) != null) {requireActivity().startActivity(intent)} else {//应用无权限打开这个设置界面,一般都有}}

3.相关的Bean对象

/*
* name : 应用名称
* packageName:包名
* icon:应用图标
* dataUsage:使用的流量字节数
* openCount:打开次数
* useTime:使用时间
* packageSize:包大小
* */data class AppBean(val name: String,val packageName: String,val icon: Drawable?,var dataUsage: Long,val openCount : Int,val useTime : Long,val packageSize : Long = 0L
)/**
* indexTime : 第i周、第i天、第i月
* timeRegion 时间的区间
* data : 显示的数据 ,如:1.2GB、1.2MB* progress : 这个Flow占所有的流量的百分比 
* */
data class Flow(var indexTime:String,var timeRegion : String ,val data:String, var progress:Int = 0)

4.统一的工具类

自己的包名import android.app.DatePickerDialog
import android.app.usage.NetworkStats
import android.app.usage.NetworkStatsManager
import android.app.usage.StorageStats
import android.app.usage.StorageStatsManager
import android.app.usage.UsageEvents
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.storage.StorageManager
import android.util.Log
import com.kodami.metoru.libui.bean.AppBean
import com.kodami.metoru.libui.bean.Flow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Socket
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.random.Randomobject FlowUtils {//获取所有应用的信息(包括icon,名称,流量使用量,打开次数,使用时间,包体大小)fun getAllInstalledAppsInfo(context: Context, startTime: Long, endTime: Long): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(0)val appBeans = mutableListOf<AppBean>()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage = getAppDataUsage(context, packageName, startTime, endTime)val pakageSize = getAppPackageSize(context, packageName)if (dataUsage > 1024) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,geAppTodayOpenCount(context, packageName),getAppUseNetworkTime(context, packageName, startTime),pakageSize))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.dataUsage }return appBeans}//获取今天所有应用的信息,通过使用流量排序fun getAllInstalledAppsInfo(context: Context): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(0)val appBeans = mutableListOf<AppBean>()val startTime = getTodayTimeInMillis()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage =getAppDataUsage(context, packageName, startTime, getEndTimeInMillis(startTime))val pakageSize = getAppPackageSize(context, packageName)if (dataUsage > 1024) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,geAppTodayOpenCount(context, packageName),getAppUseNetworkTime(context, packageName, startTime),pakageSize))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.dataUsage }return appBeans}//重载方法,默认结束结束时间是今晚0点整fun getAllInstalledAppsInfo(context: Context, startTime: Long): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(0)val appBeans = mutableListOf<AppBean>()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage = getAppDataUsage(context, packageName, startTime,getEndTimeInMillis(getTodayTimeInMillis()))if (dataUsage > 1024) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,geAppTodayOpenCount(context, packageName),getAppUseNetworkTime(context, packageName, startTime)))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.dataUsage }return appBeans}//获取今天所有应用的信息,按照使用时间排序(包括icon,名称,流量使用量,打开次数,使用时间)fun getAllInstalledAppsInfoSortByUseTime(context: Context, startTime: Long): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(0)val appBeans = mutableListOf<AppBean>()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage =getAppDataUsage(context, packageName, startTime, getEndTimeInMillis(getTodayTimeInMillis()))val useTime = getAppUseNetworkTime(context, packageName, startTime)val pakageSize = getAppPackageSize(context, packageName)if (useTime > 0) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,geAppTodayOpenCount(context, packageName),useTime,pakageSize))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.useTime }return appBeans}//获取今天所有应用的信息,按照包体大小排序(包括icon,名称,流量使用量,打开次数,使用时间)fun getAllInstalledAppsInfoSortByPackageSize(context: Context, startTime: Long): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(PackageManager.GET_ACTIVITIES orPackageManager.GET_SERVICES)val appBeans = mutableListOf<AppBean>()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage = getAppDataUsage(context, packageName, startTime,getEndTimeInMillis(getTodayTimeInMillis()))val pakageSize = getAppPackageSize(context, packageName)if (pakageSize > 1024) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,geAppTodayOpenCount(context, packageName),getAppUseNetworkTime(context, packageName, startTime),pakageSize))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.packageSize }return appBeans}//获取今天所有应用的信息,按照打开次数排序(包括icon,名称,流量使用量,打开次数,使用时间)fun getAllInstalledAppsInfoSortByOpenCount(context: Context, startTime: Long): List<AppBean> {val packageManager = context.packageManagerval packageInfoList = packageManager.getInstalledPackages(0)val appBeans = mutableListOf<AppBean>()for (packageInfo in packageInfoList) {if (!isSystemApp(packageInfo)) {  //排除掉系统级应用val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()val packageName = packageInfo.packageNameval icon = packageInfo.applicationInfo.loadIcon(packageManager)val dataUsage = getAppDataUsage(context, packageName, startTime,getEndTimeInMillis(getTodayTimeInMillis()))val openCount = geAppTodayOpenCount(context, packageName)if (openCount > 0) {appBeans.add(AppBean(appName,packageName,icon,dataUsage,openCount,getAppUseNetworkTime(context, packageName, startTime)))}}}// 按数据使用情况降序对列表进行排序appBeans.sortByDescending { it.openCount }return appBeans}//获取安装包大小fun getAppPackageSize(context: Context, packageName: String): Long {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {return 0L}val pm = context.packageManagerval appInfo: ApplicationInfo?try {appInfo = pm.getApplicationInfo(packageName, 0)} catch (e: PackageManager.NameNotFoundException) {Log.e("AppSizeError", "Package not found", e)return 0L}val statsManager = context.getSystemService(StorageStatsManager::class.java)val uuid: UUID = StorageManager.UUID_DEFAULTval pkgStats: StorageStats?try {pkgStats = statsManager.queryStatsForUid(uuid, appInfo.uid)} catch (e: Exception) {Log.e("AppSizeError", "Error getting storage stats", e)return 0L}val cacheSize = pkgStats.cacheBytes  //缓存大小val dataSize = pkgStats.dataBytes //用户数据大小val codeSize = pkgStats.appBytes //包体大小return cacheSize + dataSize + codeSize}//获取App今日打开次数fun geAppTodayOpenCount(context: Context, packageName: String): Int {val usageStatsManager =context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManagerval startTime = System.currentTimeMillis() - 1000 * 60 * 60 * 24 // Start time: 24 hours agoval endTime = System.currentTimeMillis()val events = usageStatsManager.queryEvents(startTime, endTime)var openCount = 0while (events.hasNextEvent()) {val event = UsageEvents.Event()events.getNextEvent(event)if (event.eventType == UsageEvents.Event.MOVE_TO_FOREGROUND && event.packageName != null && event.packageName == packageName) {openCount++}}return openCount}//获取app使用流量的时间fun getAppUseNetworkTime(context: Context, packageName: String, startTime: Long): Long {val usageStatsManager =context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManagerval connectivityManager =context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManagervar totalForegroundWithNetworkTime: Long = 0if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val networkCapabilities =connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)if (networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)) {val usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, startTime, getEndTimeInMillis(getTodayTimeInMillis()))if (usageStatsList != null) {for (usageStats in usageStatsList) {if (usageStats.lastTimeUsed in startTime..getEndTimeInMillis(getTodayTimeInMillis()) && usageStats.packageName == packageName) {totalForegroundWithNetworkTime += usageStats.totalTimeInForeground}}}}return totalForegroundWithNetworkTime}return 0L}private fun getUidOfPackage(context: Context, packageName: String): Int {val packageManager = context.packageManagerval applicationInfo = packageManager.getApplicationInfo(packageName, 0)return applicationInfo.uid}//查询指定应用程序在指定时间段内的移动网络使用情况fun getAppDataUsage(context: Context,packageName: String,startTime: Long,endTime: Long): Long {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {try {val networkStatsManager =context.getSystemService(Context.NETWORK_STATS_SERVICE) as NetworkStatsManagerval packageInfo = context.packageManager.getPackageInfo(packageName, 0)val uid = packageInfo.applicationInfo.uidval networkStats = networkStatsManager.querySummary(NetworkCapabilities.TRANSPORT_CELLULAR,null,startTime,endTime)var rxBytes: Long = 0var txBytes: Long = 0// 遍历网络使用情况数据,计算接收和发送的字节数val bucket = NetworkStats.Bucket()while (networkStats.hasNextBucket()) {networkStats.getNextBucket(bucket)if (bucket.uid == uid) {rxBytes += bucket.rxBytestxBytes += bucket.txBytes}}return txBytes + rxBytes} catch (e: Exception) {e.printStackTrace()}}return 0}//获取指定时间段内所有应用使用的流量字节数,默认结束时间时今晚0点整fun getAllAppDataUsage(context: Context, startTime: Long): Long {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val networkStatsManager =context.getSystemService(Context.NETWORK_STATS_SERVICE) as NetworkStatsManagerval bucketMobile: NetworkStats.Buckettry {bucketMobile = networkStatsManager.querySummaryForDevice(NetworkCapabilities.TRANSPORT_CELLULAR,null,startTime,getEndTimeInMillis(System.currentTimeMillis()))return bucketMobile.txBytes + bucketMobile.rxBytes} catch (e: Exception) {e.printStackTrace()}}return -1L}//获取指定时间段内所有应用使用的流量字节数fun getAllAppDataUsage(context: Context, startTime: Long, endTime: Long): Long {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val networkStatsManager =context.getSystemService(Context.NETWORK_STATS_SERVICE) as NetworkStatsManagerval bucketMobile: NetworkStats.Buckettry {bucketMobile = networkStatsManager.querySummaryForDevice(NetworkCapabilities.TRANSPORT_CELLULAR,null,startTime,endTime)return bucketMobile.txBytes + bucketMobile.rxBytes} catch (e: Exception) {e.printStackTrace()}}return -1L}fun getThisWeekEveryDayFlowList(context: Context): List<Flow> {var startTimeMillis = getThisWeekMondayTimeInMillis()val thisWeekEveryDayFlowList = ArrayList<Flow>()for (i in 0 until 7) {val endTimeMillis = getEndTimeInMillis(startTimeMillis, 1)val data = getByteFromMb(getAllAppDataUsage(context, startTimeMillis, endTimeMillis))val indexTime = when (i) {0 -> "周日"1 -> "周一"2 -> "周二"3 -> "周三"4 -> "周四"5 -> "周五"6 -> "周六"else -> "无效周数"}thisWeekEveryDayFlowList.add(Flow(indexTime,"${getTimeStringFromTimestamp2(startTimeMillis)}","$data MB"))startTimeMillis = endTimeMillis}return thisWeekEveryDayFlowList}//获取空值的流量列表 一般用于未授权时展示fun getNullThisWeekUseFlowList() : List<Flow> {var startTimeMillis = FlowUtils.getThisWeekMondayTimeInMillis()val thisWeekEveryDayFlowList = ArrayList<Flow>()for (i in 0 until 7) {val endTimeMillis = FlowUtils.getEndTimeInMillis(startTimeMillis, 1)val indexTime = when (i) {0 -> "星期日"1 -> "星期一"2 -> "星期二"3 -> "星期三"4 -> "星期四"5 -> "星期五"6 -> "星期六"else -> "无效周数"}thisWeekEveryDayFlowList.add(Flow(indexTime, "${FlowUtils.getTimeStringFromTimestamp2(startTimeMillis)}", "- MB"))startTimeMillis = endTimeMillis}return thisWeekEveryDayFlowList}//获取本月每日的流量列表fun getThisMonthEveryDayFlowList(context: Context): List<Flow> {var timeInMills = getThisMonthTimeInMillis()val thisMonthEveryDayFlowList = ArrayList<Flow>()for (i in 0 until getDayOfMonth()) {val data = getByteFromMb(getAllAppDataUsage(context,timeInMills,getEndTimeInMillis(timeInMills)))thisMonthEveryDayFlowList.add(Flow("${i + 1}日","${getTimeStringFromTimestamp2(timeInMills)}","$data MB"))timeInMills = getEndTimeInMillis(timeInMills)}return thisMonthEveryDayFlowList}//获取本月每周的流量列表fun getThisMonthToWeekFlowList(context: Context): ArrayList<Flow> {val thisMonthStertTimeInMillis = getThisMonthTimeInMillis()val todayEndTimeInMillis = getEndTimeInMillis(getTodayTimeInMillis())var thisTimeInMillis = thisMonthStertTimeInMillisval thisMonthEveryWeekFlowList = ArrayList<Flow>()var i = 1while (thisTimeInMillis < todayEndTimeInMillis) {val endTimeInMillis = getEndTimeInMillis(thisTimeInMillis,getDaysUntilNextSunday(thisTimeInMillis))val flowNum = getByteFromGb(getAllAppDataUsage(context,thisTimeInMillis,endTimeInMillis))val dateTime = "${getTimeStringFromTimestamp2(thisTimeInMillis)} - ${getTimeStringFromTimestamp2(endTimeInMillis)} "thisMonthEveryWeekFlowList.add(Flow("第${i}周", dateTime, "$flowNum GB"))thisTimeInMillis = endTimeInMillisi++}return thisMonthEveryWeekFlowList}//获取本年每月的流量列表fun getThisYearEveryMonthFlowList(context: Context): List<Flow> {val everyMonthTimeInMillisList = getJanuaryToNextMonthStartTimeMillisList()val thisYearEveryMonthFlowList = ArrayList<Flow>()for (i in 0 until everyMonthTimeInMillisList.size - 1) {val data = getByteFromGb(getAllAppDataUsage(context,everyMonthTimeInMillisList[i],everyMonthTimeInMillisList[i + 1]))val dateTime ="${getTimeStringFromTimestamp2(everyMonthTimeInMillisList[i])} - ${everyMonthTimeInMillisList[i + 1]} "thisYearEveryMonthFlowList.add(Flow("${i + 1}月", dateTime, "$data GB"))}return thisYearEveryMonthFlowList}//设置流量列表的中每项的进度fun setFlowListProgress(flowList: List<Flow>): List<Flow> {val max = flowList.maxByOrNull { it.data.split(" ")[0].toFloat() }?.data?.toFloat() ?: 0fif (max > 0f) {flowList.forEach {it.progress = (it.data.split(" ")[0].toFloat() / max * 1.25 * 100).toInt()}}return flowList}// 获取移动数据网络的带宽fun getMobileDataSpeed(context: Context): Int {val connectivityManager =context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManagerif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val network = connectivityManager.activeNetworkval capabilities = connectivityManager.getNetworkCapabilities(network)return capabilities?.let { capabilities.linkUpstreamBandwidthKbps + capabilities.linkDownstreamBandwidthKbps } ?: 0} else {return Random.nextInt(8192, 8192*100)}}//获取下载速度fun getUploadSpeed(context: Context): String {val connectivityManager =context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManagerif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {val network =connectivityManager.activeNetworkval capabilities = connectivityManager.getNetworkCapabilities(network)if (capabilities != null ){val speed = (capabilities.linkUpstreamBandwidthKbps / 8 / 1024).toDouble()if (speed > 0.0) {return String.format("%.1f", Random.nextDouble(0.0, speed))}}}return String.format("%.1f", Random.nextDouble(  0.0,10.0))}//字节转MBfun getByteFromMb(bytes: Long): Float {return String.format("%.1f", bytes / (1024 * 1024f)).toFloat()}//字节转GBfun getByteFromGb(bytes: Long): Float {return String.format("%.1f", bytes / (1024 * 1024 * 1024f)).toFloat()}//判断是否为系统应用fun isSystemApp(packageInfo: PackageInfo): Boolean {return packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0}//获取网络延迟suspend fun getNetworkLatency(): String {return withContext(Dispatchers.IO) {var latency = "--"try {val socket = Socket()val startTime = System.currentTimeMillis()socket.connect(InetSocketAddress("www.baidu.com", 80), 3000)  // 连接百度服务器val endTime = System.currentTimeMillis()latency = (endTime - startTime).toString()Log.d("WifiInfo", "网络延迟: $latency ms")socket.close()} catch (e: IOException) {e.printStackTrace()}latency}}//获取今年从1月到本月下一个月的每月开始日凌晨0:00的时间戳链表fun getJanuaryToNextMonthStartTimeMillisList(): List<Long> {val currentMonth = Calendar.getInstance().get(Calendar.MONTH)val currentYear = Calendar.getInstance().get(Calendar.YEAR)val timestamps = mutableListOf<Long>()val calendar = Calendar.getInstance()for (month in 0..currentMonth + 1) {calendar.clear()calendar.set(currentYear, month, 1, 0, 0, 0)timestamps.add(calendar.timeInMillis)}return timestamps}//当前年月fun getCurrentYearAndMonth(): String {val currentTime = Calendar.getInstance()val year = currentTime.get(Calendar.YEAR)val month = currentTime.get(Calendar.MONTH) + 1 // Calendar.MONTH 从 0 开始计数,所以需要加 1return "$year 年 $month 月"}//获取当前年月日fun getCurrentYearAndMonthAndDay(): String {val dateFormat = SimpleDateFormat("yyyy-MM-dd")val currentDate = Date()val formattedDate = dateFormat.format(currentDate)return formattedDate}//获取今天的在月份的天数fun getDayOfMonth(): Int {// 创建一个 Calendar 实例val calendar = Calendar.getInstance()// 将当前时间设置到 Calendar 实例中calendar.time = java.util.Date()return calendar.get(Calendar.DAY_OF_MONTH)}//流量单位转化fun getProgressFormatted(bytes: Long): String {return if (bytes < 1024) {"${bytes}B"} else if (bytes < 1024 * 1024) {String.format("%.1f", bytes / 1024f) + " KB"} else if (bytes < 1024 * 1024 * 1024) {String.format("%.1f", bytes / (1024 * 1024f)) + " MB"} else {String.format("%.1f", bytes / (1024 * 1024 * 1024f)) + " GB"}}//毫秒转化为中文时间字符串fun getMillisProgressFormattedChinese(millis: Long): String {val seconds = millis / 1000return when {seconds < 1 -> "${millis}毫秒"seconds < 60 -> "${seconds}秒"seconds < 3600 -> {val minutes = seconds / 60val remainingSeconds = seconds % 60"${minutes}分${remainingSeconds}秒"}else -> {val hours = seconds / 3600val remainingMinutes = (seconds % 3600) / 60"${hours}小时${remainingMinutes}分钟"}}}//毫秒单位转化fun getMillisProgressFormatted(millis: Long): String {val seconds = millis / 1000return when {seconds < 1 -> "${millis}ms"seconds < 60 -> "${seconds}s"seconds < 3600 -> {val minutes = seconds / 60val remainingSeconds = seconds % 60"${minutes}min${remainingSeconds}s"}else -> {val hours = seconds / 3600val remainingMinutes = (seconds % 3600) / 60val remainingSeconds = seconds % 60"${hours}h${remainingMinutes}min${remainingSeconds}s"}}}//获取本月总天数fun getThisMonthAllDayNum(): Int {val calendar = Calendar.getInstance()val year = calendar[Calendar.YEAR]val month = calendar[Calendar.MONTH]calendar[year, month] = 1 // 设置为本月的第一天return calendar.getActualMaximum(Calendar.DAY_OF_MONTH)}//获取今天的星期数fun getDayOfWeek(): Int {// 创建一个 Calendar 实例val calendar = Calendar.getInstance()// 将当前时间设置到 Calendar 实例中calendar.time = java.util.Date()// 获取今天的星期数,星期日为 1,星期一为 2,以此类推return calendar.get(Calendar.DAY_OF_WEEK)}//获取传入时间戳的星期数fun getDayOfWeek(timestamp: Long): String {val calendar = Calendar.getInstance()calendar.timeInMillis = timestampval dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)val days =arrayOf("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")return days[dayOfWeek - 1]}//获取本周开始日(周日)凌晨的时间戳fun getThisWeekMondayTimeInMillis(): Long {val calendar = Calendar.getInstance()calendar.firstDayOfWeek = Calendar.SUNDAYcalendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)calendar.set(Calendar.HOUR_OF_DAY, 0)calendar.set(Calendar.MINUTE, 0)calendar.set(Calendar.SECOND, 0)calendar.set(Calendar.MILLISECOND, 0)// 返回时间戳return calendar.timeInMillis}//获取传入时间戳距离下周开始日(周末)的天数fun getDaysUntilNextSunday(timestamp: Long): Int {val calendar = Calendar.getInstance().apply {timeInMillis = timestamp}val currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)val daysUntilNextSunday = 8 - currentDayOfWeek // 计算距离下一周开始日(星期日)的天数return daysUntilNextSunday}//获取本月开始日凌晨的时间戳fun getThisMonthTimeInMillis(): Long {val cal = Calendar.getInstance()cal[cal[Calendar.YEAR], cal[Calendar.MONTH], cal[Calendar.DAY_OF_MONTH], 0, 0] =0cal[Calendar.DAY_OF_MONTH] = cal.getActualMinimum(Calendar.DAY_OF_MONTH)return cal.timeInMillis}//获取今天凌晨的时间戳fun getTodayTimeInMillis(): Long {val calendar = Calendar.getInstance()calendar.set(Calendar.HOUR_OF_DAY, 0)calendar.set(Calendar.MINUTE, 0)calendar.set(Calendar.SECOND, 0)calendar.set(Calendar.MILLISECOND, 0)return calendar.timeInMillis}//获取传入时间下一天凌晨的时间戳fun getEndTimeInMillis(startTime: Long): Long {val calendar = Calendar.getInstance()calendar.timeInMillis = startTimecalendar.add(Calendar.DAY_OF_MONTH, 1) // 加一天calendar.set(Calendar.HOUR_OF_DAY, 0)calendar.set(Calendar.MINUTE, 0)calendar.set(Calendar.SECOND, 0)calendar.set(Calendar.MILLISECOND, 0)return calendar.timeInMillis}//获取传入时间几天前/后凌晨的时间戳fun getEndTimeInMillis(startTime: Long, i: Int): Long {val calendar = Calendar.getInstance()calendar.timeInMillis = startTimecalendar.add(Calendar.DAY_OF_MONTH, i) // 增加/减少i天calendar.set(Calendar.HOUR_OF_DAY, 0)calendar.set(Calendar.MINUTE, 0)calendar.set(Calendar.SECOND, 0)calendar.set(Calendar.MILLISECOND, 0)return calendar.timeInMillis}//获取几天前凌晨的时间戳fun getStartTimeInMillis(i: Int): Long {val calendar = Calendar.getInstance()calendar.timeInMillis = System.currentTimeMillis()calendar.add(Calendar.DAY_OF_YEAR, i) // 增加/减少i天calendar.set(Calendar.HOUR_OF_DAY, 0) // 设置小时为零calendar.set(Calendar.MINUTE, 0) // 设置分钟为零calendar.set(Calendar.SECOND, 0) // 设置秒数为零calendar.set(Calendar.MILLISECOND, 0) // 设置毫秒为零return calendar.timeInMillis}//获取现在的时间fun getCurrentTime(): String {val currentTime = Calendar.getInstance().timeval dateFormat = SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault())return dateFormat.format(currentTime)}//获取日期的时间戳fun getTimestampAtMidnight(year: Int, month: Int, dayOfMonth: Int): Long {val calendar = Calendar.getInstance(TimeZone.getDefault())calendar.set(Calendar.YEAR, year)calendar.set(Calendar.MONTH, month - 1) // 注意:Java Calendar月份是从0开始的calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)calendar.set(Calendar.HOUR_OF_DAY, 0)calendar.set(Calendar.MINUTE, 0)calendar.set(Calendar.SECOND, 0)calendar.set(Calendar.MILLISECOND, 0)return calendar.timeInMillis}//通过时间戳获取时间fun getTimeStringFromTimestamp(timestamp: Long): String {val sdf = SimpleDateFormat("yyyy/MM/dd HH:mm", Locale.getDefault())return sdf.format(Date(timestamp))}fun getTimeStringFromTimestamYMD(timestamp: Long): String {val sdf = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault())return sdf.format(Date(timestamp))}fun getTimeStringFromTimestampD(timestamp: Long): String {val sdf = SimpleDateFormat("d", Locale.getDefault())return sdf.format(Date(timestamp))}fun getTimeStringFromTimestamp2(timestamp: Long): String {val sdf = SimpleDateFormat("MM.dd", Locale.getDefault())return sdf.format(Date(timestamp))}fun getTimeStringFromTimestampMDD(timestamp: Long): String {val sdf = SimpleDateFormat("M.dd", Locale.getDefault())return sdf.format(Date(timestamp))}//计算两个时间戳相差的天数fun daysBetweenTimestamps(startTimestamp: Long, endTimestamp: Long): Long {// 创建 Calendar 实例val calendarStart = Calendar.getInstance()val calendarEnd = Calendar.getInstance()// 设置 Calendar 对象的时间为指定的时间戳calendarStart.timeInMillis = startTimestampcalendarEnd.timeInMillis = endTimestamp// 计算两个时间戳之间的差值(毫秒)val diffInMillis = calendarEnd.timeInMillis - calendarStart.timeInMillisreturn Math.abs(TimeUnit.MILLISECONDS.toDays(diffInMillis))}//显示选择日期的日历dialogfun showDatePickerDialog(context: Context, calendar: Calendar = Calendar.getInstance(), onDateSet: (year: Int, month: Int, day: Int) -> Unit ) {DatePickerDialog(context,{ _, year, monthOfYear, dayOfMonth ->onDateSet(year, monthOfYear + 1, dayOfMonth)},calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),calendar.get(Calendar.DAY_OF_MONTH)).show()}}

5. 其他

5.1导入后面需要的包

   //协程api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"api "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"api "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"//retrofitimplementation 'com.squareup.retrofit2:retrofit:2.6.1'implementation 'com.squareup.retrofit2:converter-gson:2.6.1'

5.2获取IP相关信息和下载速度的接口

5.2.1  接口服务类

interface RetrofitService {@Streaming@GETfun downloadFile(@Url fileUrl: String): Call<ResponseBody>@GET("jsonp")fun getGeoLocation( @Query("ip")  ip : String?): Call<ResponseBody>@GET("jsonp")fun getGeoLocation(): Call<ResponseBody>
}

 5.2.3 ip的Bean

data class IpInfo(val country: String?,val shortName: String?,val province: String?,val city: String?,val area: String?,val isp: String?,val net: String?,val ip: String?,val code: Int?,val desc: String?
){constructor() : this("--","--","--","--","--","--","--","--",0,"--")}

 5.2.3 实现类

package 你的包名import android.content.Context
import android.os.Environment
import android.util.Log
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.io.FileOutputStreamclass RetrofitImpl {//获取下载速度suspend fun getDownloadSpeed(context: Context): String {val retrofit = Retrofit.Builder().baseUrl("https://dldir1.qq.com/").build()val service = retrofit.create(RetrofitService::class.java)return withContext(Dispatchers.IO) {val call =service.downloadFile("qqfile/qq/QQNT/Windows/QQ_9.9.7_240305_x86_01.exe").execute()if (call.isSuccessful) {val body = call.body()if (body != null) {val startTime = System.currentTimeMillis()val inputStream = body.byteStream()val file =File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "qq.apk")val fileOutputStream = FileOutputStream(file)val buffer = ByteArray(4096)var bytesRead: Intvar totalBytesRead = 0while (inputStream.read(buffer).also { bytesRead = it } != -1) {fileOutputStream.write(buffer, 0, bytesRead)totalBytesRead += bytesReadval currentTime = System.currentTimeMillis()if (currentTime - startTime >= 1000) {val totalTime = currentTime - startTimeval speedBytesPerSecond = totalBytesRead.toFloat() / totalTime * 1000val speedMegaBytesPerSecond =String.format("%.1f", speedBytesPerSecond / (1024 * 1024))Log.d("RetrofitImpl", "Download speed: ${speedMegaBytesPerSecond} MB/s")fileOutputStream.close()inputStream.close()return@withContext speedMegaBytesPerSecond}}// 如果在一秒内下载未完成,则直接关闭流fileOutputStream.close()inputStream.close()}}return@withContext "-- Mb/s"}}//查询公网Ip对于的信息 包括所属省份、城市、运营商、网络类型等suspend fun getGeoLocation(ipAddress: String?): IpInfo {val BASE_URL = "https://ip.useragentinfo.com/"val httpClient = OkHttpClient.Builder().build()val retrofit = Retrofit.Builder().baseUrl(BASE_URL).client(httpClient).addConverterFactory(GsonConverterFactory.create()).build()val service = retrofit.create(RetrofitService::class.java)return withContext(Dispatchers.IO) {val response = if (ipAddress == null) {service.getGeoLocation().execute()  //查询本客户端}else{service.getGeoLocation(ipAddress).execute()}if (response.isSuccessful) {val responsedata = response.body()?.string()val data = Gson().fromJson(responsedata.toString().substring(9, responsedata!!.length - 2), IpInfo::class.java)Log.d("RetrofitImpl","获取公网Ip信息"+data.toString())return@withContext data}return@withContext IpInfo()}}
}

6.示例

fun getAndUpdateData() {CoroutineScope(Dispatchers.IO).launch {//下载速度val  downloadSpeed = RetrofitImpl().getDownloadSpeed(context)//网络延迟val networLatency = FlowUtils.getNetworkLatency()//网络带宽val mobileData = FlowUtils.getMobileDataSpeed(context)//今日使用的总流量数todayUseFlow = FlowUtils.getByteFromMb(FlowUtils.getAllAppDataUsage(requireContext(),FlowUtils.getTodayTimeInMillis()))//本月使用的总流量数thisMonthUseFlow = FlowUtils.getByteFromGb(FlowUtils.getAllAppDataUsage(requireContext(),FlowUtils.getThisMonthTimeInMillis()))//本周使用的总流量数thisWeekUseFlow = FlowUtils.getByteFromGb(FlowUtils.getAllAppDataUsage(requireContext(),FlowUtils.getThisWeekMondayTimeInMillis()))//今日流量使用情况的appBean列表val todayApps = FlowUtils.getAllInstalledAppsInfo(requireContext(),FlowUtils.getTodayTimeInMillis())//本周流量使用情况的appBean列表val thisWeekApps = FlowUtils.getAllInstalledAppsInfo(requireContext(),FlowUtils.getThisWeekMondayTimeInMillis())//本月流量使用情况的appBean列表val thisMonthApps = FlowUtils.getAllInstalledAppsInfo(requireContext(),FlowUtils.getThisMonthTimeInMillis())withContext(Dispatchers.Main) {//展示和处理相关数据}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/64300.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第17天:信息收集-Web应用备案产权Whois反查域名枚举DNS记录证书特征相似查询

#知识点 1、信息收集-Web应用-机构产权&域名相关性 2、信息收集-Web应用-DNS&证书&枚举子域名 标签 名称 地址 企业信息 天眼查 天眼查-商业查询平台_企业信息查询_公司查询_工商查询_企业信用信息系统 企业信息 小蓝本 获客营销系统_ai智能拓客系统_企业获…

在循环群模运算中计算逆元

文章目录 一、算数模复合二、群 循环群1. 群 (Group)2. 环 (Ring)3. 循环群 (Cyclic Group)4. 多项式环 (Polynomial Ring)5. 有限域 (Finite Field)6. 椭圆曲线 (Elliptic Curve) 三、求逆元1. 扩展欧几里得算法1.1 算法概述1.2 步骤1.3 示例 2. 费马小定理 一、算数模复合 假…

Python使用Selenium库获取 网页节点元素、名称、内容的方法

我们要用到一些网页源码信息&#xff0c;例如获取一些节点的class内容&#xff0c; 除了使用Beautifulsoup来解析&#xff0c;还可以直接用Selenium库打印节点&#xff08;元素&#xff09;名称&#xff0c;用来获取元素的文本内容或者标签名。 例如获取下面的class的内容&am…

M3DM的autodl环境构建过程笔记

文章目录 在3D-ADS环境https://blog.csdn.net/tfxzgp/article/details/144259472基础上构建M3DM(失败的记录&#xff0c;不用看)更换镜像重来&#xff08;成功&#xff09;安装缺少的包修改models.py中的RGB和点云backbone的路径修改main.py路径参数运行 在3D-ADS环境https://b…

Android 使用Overlay现实主题切换

最近项目上&#xff0c;想做一个主题切换的功能&#xff0c;整理了一下发布出来&#xff0c;主要使用的是IOverlayManager&#xff0c;大体思路如下&#xff1a; 1、想切换的应用&#xff0c;各自做overlay apk&#xff08;简称皮肤包&#xff09; 2、将overlay apk push 到v…

【原生js案例】如何实现一个穿透字体颜色的导航

普通的导航大家都会做&#xff0c;像这种穿透字体的导航应该很少见吧。高亮不是通过单独设置一个active类来设置字体高亮颜色&#xff0c;鼠标滑过导航项&#xff0c;字体可以部分是黑色&#xff0c;不分是白色&#xff0c;这种效果的实现 感兴趣的可以关注下我的系列课程【we…

IDEA 2023.3.6 下载、安装、激活与使用

一、IDEA2023.3.6下载 国际官网&#xff1a;https://www.jetbrains.com/ 国内官网&#xff1a;https://www.jetbrains.com.cn/ 如果国际官网无法访问&#xff0c;就使用国内官网&#xff0c;我们以国内官网为例下载IDEA2023.3.6 首先进入首页如下图&#xf…

ip_done

文章目录 路由结论 IP分片 数据链路层重谈Mac地址MAC帧报头局域网的通信原理MSS&#xff0c;以及MAC帧对上层的影响ARP协议 1.公司是不是这样呢? 类似的要给运营商交钱&#xff0c;构建公司的子网&#xff0c;具有公司级别的入口路由器 2&#xff0e;为什么要这样呢?? IP地…

Unity 将数字1234转换为字母ABCD

需求如下&#xff1a; 数字1&#xff0c;转换后为&#xff1a;A 数字2&#xff0c;转换后为&#xff1a;B 数字3&#xff0c;转换后为&#xff1a;C 数字4&#xff0c;转换后为&#xff1a;D 数字123&#xff0c;转换后为&#xff1a;ABC C#实现代码如下&#xff1a; pri…

深度学习作业 - 作业十一 - LSTM

问题一 推导LSTM网络中参数的梯度&#xff0c;并的分析其避免梯度消失的效果 LSTM网络是为了解简单RNN中存在的长程依赖问题而提出的一种新型网络结构&#xff0c;其主要思想是通过引入门控机制来控制数据的流通&#xff0c;门控机制包括输入门、遗忘门与输出门&#xff0c;同…

医院与医疗设备供应商网络安全事故综述

医院与医疗设备供应商网络安全事故综述 在医疗行业中&#xff0c;医院和医疗设备供应商的网络安全问题同样不容忽视。以下是一些近年来发生的重大网络安全事故的总结&#xff1a; 1. 德国杜塞尔多夫大学医院勒索软件攻击&#xff08;2020年&#xff09; 事件描述&#xff1a…

修改vscode中emmet中jsx和tsx语法中className的扩展符号从单引号到双引号 - HTML代码补全 - 单引号双引号

效果图 实现步骤 文件 > 首选项 > 设置搜索“”在settings.json中修改&#xff0c;增加 "emmet.syntaxProfiles": {"html": {"attr_quotes": "single"},"jsx": {"attr_quotes": "double","…

从0到1实现vue3+vite++elementuiPlus+ts的后台管理系统(一)

前言&#xff1a;从这篇文章开始实现vue3vite的后台管理系统&#xff0c;记录下自己搭建后台系统图的过程。 这篇文章完成项目的初始化和基本配置&#xff0c;这一步可以直接跟着vue3官网进行。整个系列只有前端部分&#xff0c;不涉及后端。 vue3官网&#xff1a;https://cn.…

JavaEE初阶——多线程(线程安全-锁)

复习上节内容&#xff08;部分-掌握程度不够的&#xff09; 加锁&#xff0c;解决线程安全问题。 synchronized关键字&#xff0c;对锁对象进行加锁。 锁对象&#xff0c;可以是随便一个Object对象&#xff08;或者其子类的对象&#xff09;&#xff0c;需要关注的是&#xff…

如何在NGINX中实现基于IP的访问控制(IP黑白名单)?

大家好&#xff0c;我是锋哥。今天分享关于【如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f;】面试题。希望对大家有帮助&#xff1b; 如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f; 1000道 互联网大…

Docker--Docker Registry(镜像仓库)

什么是Docker Registry&#xff1f; 镜像仓库&#xff08;Docker Registry&#xff09;是Docker生态系统中用于存储、管理和分发Docker镜像的关键组件。 镜像仓库主要负责存储Docker镜像&#xff0c;这些镜像包含了应用程序及其相关的依赖项和配置&#xff0c;是构建和运行Doc…

微信小程序:实现节点进度条的效果;正在完成的节点有动态循环效果;横向,纵向排列

参考说明 微信小程序实现流程进度功能 - 知乎 上面的为一个节点进度条的例子&#xff0c;但并不完整&#xff0c;根据上述代码&#xff0c;进行修改完善&#xff0c;实现其效果 横向效果 代码 wxml <view classorder_process><view classprocess_wrap wx:for&quo…

window下的qt5.14.2配置vs2022

这里做一个笔记&#xff0c;已知qt5.14.2和vs2022不兼容&#xff0c;无法自动扫描到vs的编译器。但由于团队协作原因&#xff0c;必须使用qt5.14.2&#xff0c;并且第三方库又依赖vs2022。其实qt5.15.2是支持vs2022的&#xff0c;如果能够用qt5.15.2&#xff0c;还是建议使用qt…

2.metagpt中的软件公司智能体 (ProductManager 角色)

1. 代码 ProductManager 类 from metagpt.actions import UserRequirement, WritePRD from metagpt.actions.prepare_documents import PrepareDocuments from metagpt.roles.role import Role, RoleReactMode from metagpt.utils.common import any_to_nameclass ProductMan…

Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…