UsageStatsManager时间范围错误:如何正确限制应用使用统计查询区间?
解决UsageStatsManager查询应用时长包含前一天数据的问题
看起来你遇到了UsageStatsManager.queryUsageStats的一个常见坑——这个方法不会严格按照你传入的start和end返回精确匹配的统计数据,而是会返回与该时间范围有重叠的完整时间区间块(对应你指定的INTERVAL_DAILY)。
问题根源
当使用INTERVAL_DAILY时,系统的统计是按自然日划分的:每个UsageStats对象对应一个从当天00:00到次日00:00的完整日统计。你设置的start是30号00:01,刚好卡在29号统计区间的末尾和30号区间的开头之间,系统会误判这个范围与前一天的统计区间有重叠,因此返回了额外的结果。
解决方案
1. 对齐查询区间到完整自然日
首先把你的start和end调整为目标日期的精确首尾时间,避免卡在两个区间的交界处:
// 设置目标日期的00:00:00.000作为起始时间 Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); long start = calendar.getTimeInMillis(); // 设置目标日期的23:59:59.999作为结束时间 Calendar endCalendar = Calendar.getInstance(); endCalendar.setTime(date); endCalendar.set(Calendar.HOUR_OF_DAY, 23); endCalendar.set(Calendar.MINUTE, 59); endCalendar.set(Calendar.SECOND, 59); endCalendar.set(Calendar.MILLISECOND, 999); long end = endCalendar.getTimeInMillis(); // 执行查询 final List<UsageStats> usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, start, end);
2. 手动过滤不符合目标区间的结果
即使调整了时间范围,部分系统版本仍可能返回相邻日期的统计块,所以需要遍历结果,只保留完全落在目标区间内的UsageStats对象:
List<UsageStats> filteredStats = new ArrayList<>(); SimpleDateFormat df = new SimpleDateFormat("dd.MM.yy HH:mm"); for (UsageStats stats : usageStatsList) { long statsStart = stats.getFirstTimeStamp(); long statsEnd = stats.getLastTimeStamp(); // 检查当前统计块的时间是否完全在目标日期范围内 if (statsStart >= start && statsEnd <= end) { filteredStats.add(stats); // 可选:打印验证过滤结果 System.out.println("保留应用:" + stats.getPackageName() + ",统计区间:" + df.format(new Date(statsStart)) + " ~ " + df.format(new Date(statsEnd))); } }
额外注意事项
- 确保你的应用已经获取
PACKAGE_USAGE_STATS权限,并且用户在设置 > 应用 > 特殊应用权限 > 使用情况访问权限中授予了权限(Android 6.0及以上需要)。 - Android 10+ 版本中,若需查询其他应用的统计数据,可能还需要
QUERY_ALL_PACKAGES权限(除非你在Manifest中声明了特定包名)。
内容的提问来源于stack exchange,提问作者Nico Hennrich
相关产品推荐
相关产品推荐

