如何获取Android系统中各应用的屏幕使用时间及区分运行时长?
获取Android应用屏幕使用时间的实现方案
嘿,要获取Android系统中其他应用的屏幕使用时间(也就是用户实际交互的前台时长,区别于后台挂着的运行时长),核心是用Android官方提供的UsageStatsManager API,但得先搞定权限和版本适配问题,我给你理清楚具体步骤:
一、核心权限要求
首先你需要申请ACCESS_APP_USAGE_STATS权限,这是一个敏感系统权限,不能通过常规的requestPermissions()方法直接请求,必须引导用户手动到系统设置中开启权限。
权限检查与引导代码示例(Kotlin)
private fun hasUsageStatsPermission(): Boolean { val appOps = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val mode = appOps.checkOpNoThrow( AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), packageName ) return mode == AppOpsManager.MODE_ALLOWED } private fun requestUsageStatsPermission() { // 跳转到应用使用权限设置页面 startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)) }
在你的Activity初始化时,先调用hasUsageStatsPermission()检查权限,没有的话就调用requestUsageStatsPermission()引导用户开启。
二、查询屏幕使用时间(前台时长)
从Android 5.0(API 21)开始,UsageStatsManager就提供了查询应用使用统计的能力,其中totalTimeInForeground字段就是我们要的屏幕使用时间(单位:毫秒),这个值代表应用处于前台活动状态、用户实际交互的时长,和后台运行时长完全区分开。
查询指定时间区间的应用前台时长代码示例(Kotlin)
private fun getAppForegroundUsage(startTime: Long, endTime: Long): List<Pair<String, Long>> { val usageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager // 查询指定时间区间内的使用统计数据,INTERVAL_DAILY可根据需求替换 val usageStatsList = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, startTime, endTime ) return usageStatsList.mapNotNull { stats -> // 过滤掉没有前台使用记录的应用 if (stats.totalTimeInForeground > 0) { // 获取应用名称(从包名转换) val appName = try { packageManager.getApplicationLabel( packageManager.getApplicationInfo(stats.packageName, 0) ).toString() } catch (e: PackageManager.NameNotFoundException) { stats.packageName // 如果找不到应用信息,就用包名代替 } // 返回应用名称和前台时长(毫秒) appName to stats.totalTimeInForeground } else null }.sortedByDescending { it.second } // 按前台时长从长到短排序 }
调用示例(获取今日的屏幕使用时间)
val calendar = Calendar.getInstance() calendar.set(Calendar.HOUR_OF_DAY, 0) calendar.set(Calendar.MINUTE, 0) calendar.set(Calendar.SECOND, 0) val startTime = calendar.timeInMillis val endTime = System.currentTimeMillis() val appUsageList = getAppForegroundUsage(startTime, endTime) // 遍历输出,把毫秒转成小时:时长 / 3600000 appUsageList.forEach { (appName, foregroundTime) -> val hours = foregroundTime / 3600000.0 Log.d("AppUsage", "$appName 屏幕使用时间:%.2f小时".format(hours)) }
三、关键注意事项
- 版本适配:
UsageStatsManager仅在Android 5.0及以上可用,低于该版本的系统无法通过官方API获取此数据。 - 权限有效性:即使用户开启了权限,系统也可能会在应用长时间未使用后回收权限,所以每次查询前都要重新检查权限状态。
- 运行时长vs屏幕使用时间:你提到的“运行时长”如果包含后台服务时间,
UsageStatsManager并没有直接提供这个字段,若需要的话,可能需要结合ActivityManager的相关API,但Android 8.0及以上对后台进程的获取有严格限制,很难拿到准确的后台运行时长。而totalTimeInForeground是官方认可的、最准确的用户实际屏幕使用时间统计。
内容的提问来源于stack exchange,提问作者Yusuf gndz




