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.Random
object FlowUtils {
//获取所有应用的信息(包括icon,名称,流量使用量,打开次数,使用时间,包体大小)
fun getAllInstalledAppsInfo(context: Context, startTime: Long, endTime: Long): List<AppBean> {
val packageManager = context.packageManager
val 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.packageName
val 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.packageManager
val 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.packageName
val 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.packageManager
val 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.packageName
val 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.packageManager
val 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.packageName
val 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.packageManager
val packageInfoList = packageManager.getInstalledPackages(
PackageManager.GET_ACTIVITIES or
PackageManager.GET_SERVICES
)
val appBeans = mutableListOf<AppBean>()
for (packageInfo in packageInfoList) {
if (!isSystemApp(packageInfo)) { //排除掉系统级应用
val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()
val packageName = packageInfo.packageName
val 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.packageManager
val 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.packageName
val 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.packageManager
val 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_DEFAULT
val 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 UsageStatsManager
val startTime = System.currentTimeMillis() - 1000 * 60 * 60 * 24 // Start time: 24 hours ago
val endTime = System.currentTimeMillis()
val events = usageStatsManager.queryEvents(startTime, endTime)
var openCount = 0
while (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 UsageStatsManager
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
var totalForegroundWithNetworkTime: Long = 0
if (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.packageManager
val 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 NetworkStatsManager
val packageInfo = context.packageManager.getPackageInfo(packageName, 0)
val uid = packageInfo.applicationInfo.uid
val networkStats = networkStatsManager.querySummary(
NetworkCapabilities.TRANSPORT_CELLULAR,
null,
startTime,
endTime
)
var rxBytes: Long = 0
var txBytes: Long = 0
// 遍历网络使用情况数据,计算接收和发送的字节数
val bucket = NetworkStats.Bucket()
while (networkStats.hasNextBucket()) {
networkStats.getNextBucket(bucket)
if (bucket.uid == uid) {
rxBytes += bucket.rxBytes
txBytes += 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 NetworkStatsManager
val bucketMobile: NetworkStats.Bucket
try {
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 NetworkStatsManager
val bucketMobile: NetworkStats.Bucket
try {
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 = thisMonthStertTimeInMillis
val thisMonthEveryWeekFlowList = ArrayList<Flow>()
var i = 1
while (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 = endTimeInMillis
i++
}
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() ?: 0f
if (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 ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val 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 ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network =connectivityManager.activeNetwork
val 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))
}
//字节转MB
fun getByteFromMb(bytes: Long): Float {
return String.format("%.1f", bytes / (1024 * 1024f)).toFloat()
}
//字节转GB
fun 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 开始计数,所以需要加 1
return "$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 / 1000
return when {
seconds < 1 -> "${millis}毫秒"
seconds < 60 -> "${seconds}秒"
seconds < 3600 -> {
val minutes = seconds / 60
val remainingSeconds = seconds % 60
"${minutes}分${remainingSeconds}秒"
}
else -> {
val hours = seconds / 3600
val remainingMinutes = (seconds % 3600) / 60
"${hours}小时${remainingMinutes}分钟"
}
}
}
//毫秒单位转化
fun getMillisProgressFormatted(millis: Long): String {
val seconds = millis / 1000
return when {
seconds < 1 -> "${millis}ms"
seconds < 60 -> "${seconds}s"
seconds < 3600 -> {
val minutes = seconds / 60
val remainingSeconds = seconds % 60
"${minutes}min${remainingSeconds}s"
}
else -> {
val hours = seconds / 3600
val remainingMinutes = (seconds % 3600) / 60
val 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 = timestamp
val 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.SUNDAY
calendar.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] =
0
cal[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 = startTime
calendar.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 = startTime
calendar.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().time
val 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 = startTimestamp
calendarEnd.timeInMillis = endTimestamp
// 计算两个时间戳之间的差值(毫秒)
val diffInMillis = calendarEnd.timeInMillis - calendarStart.timeInMillis
return Math.abs(TimeUnit.MILLISECONDS.toDays(diffInMillis))
}
//显示选择日期的日历dialog
fun 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"
//retrofit
implementation '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
@GET
fun 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.FileOutputStream
class 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: Int
var totalBytesRead = 0
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
fileOutputStream.write(buffer, 0, bytesRead)
totalBytesRead += bytesRead
val currentTime = System.currentTimeMillis()
if (currentTime - startTime >= 1000) {
val totalTime = currentTime - startTime
val speedBytesPerSecond = totalBytesRead.toFloat() / totalTime * 1000
val 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) {
//展示和处理相关数据
}
}
}