Android开发:如何通过Usage Stats API计算应用使用时长?
嘿,我来帮你搞定Android应用里计算使用时长的问题!结合你的需求和已经做的工作,我给你两种可行的方案:
解决方案:计算应用使用时长的两种方式
1. 直接利用UsageStats API的原生字段(推荐)
其实你不用自己手动存储时间戳数组来计算时长——Android的UsageStats对象本身就包含了单次会话的开始、结束时间,以及总使用时长的字段,系统已经帮你处理好了应用前后台切换的会话划分,准确性更高。
核心思路
每个UsageStats实例对应一个应用的一段前台使用会话:
getFirstTimeStamp():会话开始的时间戳(应用进入前台的时间)getLastTimeStamp():会话结束的时间戳(应用退到后台的时间)- 两者的差值就是这段会话的使用时长,你可以按应用分组,整理成你需要的格式。
示例代码(Kotlin)
// 获取UsageStatsManager实例 val usageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val endTime = System.currentTimeMillis() val startTime = endTime - 24 * 60 * 60 * 1000 // 查询最近24小时的使用记录 // 查询使用统计数据 val usageStatsList = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, startTime, endTime ) // 按应用包名分组,整理成你需要的格式 val appUsageRecords = mutableMapOf<String, MutableList<Triple<String, Long, String>>>() for (stats in usageStatsList) { val packageName = stats.packageName // 转换时间戳为HH:mm格式 val sessionStartTimeStr = SimpleDateFormat("HH:mm", Locale.getDefault()) .format(Date(stats.firstTimeStamp)) // 计算会话时长(转成分钟) val sessionDurationMins = TimeUnit.MILLISECONDS.toMinutes( stats.lastTimeStamp - stats.firstTimeStamp ) // 存入Map,按应用分组 appUsageRecords.getOrPut(packageName) { mutableListOf() } .add(Triple(sessionStartTimeStr, sessionDurationMins, "mins")) } // 遍历输出,就和你给出的示例格式一致了 appUsageRecords.forEach { (appName, records) -> records.forEach { (time, duration, unit) -> println("$appName $time $duration $unit") } }
2. 基于你已存储的时间戳数组计算
如果你已经手动存储了应用的时间戳数组,那需要先明确这些时间戳的含义:是应用每次进入前台的时间点,还是包含进入/退出的成对时间?
核心思路(假设存储的是「进入前台」的时间点)
- 把所有应用的时间戳按时间顺序排序(不管所属应用)
- 遍历排序后的列表:
- 当前条目的结束时间 = 下一个条目的时间戳(如果存在)
- 最后一个条目的结束时间 = 当前系统时间
- 时长 = 结束时间 - 当前条目的时间戳
- 按应用整理结果即可。
示例代码(Kotlin)
// 假设你已存储的时间戳数组(示例数据,包名+时间戳) val storedAppTimestamps = listOf( Pair("Facebook", 12*60*60*1000 + 59*60*1000), // 12:59 Pair("Quora", 13*60*60*1000 + 30*60*1000), // 1:30 Pair("Facebook", 13*60*60*1000 + 45*60*1000) // 1:45 ) // 按时间戳排序 val sortedTimestamps = storedAppTimestamps.sortedBy { it.second } val usageResults = mutableListOf<String>() for (i in sortedTimestamps.indices) { val (appName, startTime) = sortedTimestamps[i] // 确定结束时间 val endTime = if (i < sortedTimestamps.size - 1) { sortedTimestamps[i+1].second } else { System.currentTimeMillis() } // 计算时长(转分钟) val durationMins = TimeUnit.MILLISECONDS.toMinutes(endTime - startTime) // 转换时间为HH:mm格式 val timeStr = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date(startTime)) // 拼接成你需要的格式 usageResults.add("$appName $timeStr $durationMins mins") } // 输出结果 usageResults.forEach { println(it) }
重要注意事项
- 确保你的应用已经获取了
android.permission.PACKAGE_USAGE_STATS权限:这个权限不能通过常规的requestPermissions()申请,需要引导用户到「设置 > 安全 > 有权查看使用情况的应用」中手动开启。 - 时区问题:存储时间戳时建议用UTC时间,避免不同时区转换导致的时长计算错误。
- 系统兼容性:部分系统应用或定制ROM可能不会正确上报使用状态,需要做兼容处理。
内容的提问来源于stack exchange,提问作者MrRobot9




