Java中如何获取其他应用后台RunningTasks并判断其运行状态
实现指定包名应用后台运行状态检测
原代码存在的核心问题
- 判断条件写错:仅检测了
IMPORTANCE_FOREGROUND前台进程,完全没有覆盖后台运行的进程场景,和检测后台任务的需求不匹配 - 弹窗逻辑错误:在遍历进程的内层循环里做判断,每遍历到一个不匹配的包名就弹一次提示,会出现大量重复弹窗、结果误判
- 返回值无效:无论检测结果如何固定返回
true,方法返回值没有实际判断意义 - 缺少版本适配:Android 5.0之后系统对进程获取接口做了严格限制,普通应用调用
getRunningAppProcesses无法拿到完整的第三方应用进程列表,直接使用会出现检测结果不准的问题
适配全版本的实现代码
首先在AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
核心检测逻辑实现:
/** * 检测指定包名应用是否处于后台运行状态 * @param packageName 待检测的目标应用包名,如com.example.app * @return 目标应用在后台运行返回true,否则返回false */ public boolean isAppRunningInBackground(String packageName) { ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); boolean isBackgroundRunning = false; // Android 5.0以下版本直接通过进程列表判断 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { List<ActivityManager.RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses(); if (runningProcesses == null) { Toast.makeText(this, "App is not running", Toast.LENGTH_LONG).show(); return false; } for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { // 排除前台进程、前台服务进程,只匹配后台进程 if (processInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && processInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) { for (String activePkg : processInfo.pkgList) { if (TextUtils.equals(activePkg, packageName)) { isBackgroundRunning = true; break; } } } if (isBackgroundRunning) break; } } else { // Android 5.0及以上版本通过UsageStatsManager结合进程存活状态判断 UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); long currentTime = System.currentTimeMillis(); // 查询最近10秒内的应用使用记录 List<UsageStats> usageStatsList = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_BEST, currentTime - 10 * 1000, currentTime ); if (usageStatsList == null || usageStatsList.isEmpty()) { // 无权限时引导用户跳转设置开启使用情况访问权限 Toast.makeText(this, "请先授予使用情况访问权限", Toast.LENGTH_LONG).show(); startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); Toast.makeText(this, "App is not running", Toast.LENGTH_LONG).show(); return false; } // 按最后使用时间排序,获取当前栈顶应用 TreeMap<Long, UsageStats> taskSortMap = new TreeMap<>(); for (UsageStats stats : usageStatsList) { taskSortMap.put(stats.getLastTimeUsed(), stats); } UsageStats topTask = taskSortMap.get(taskSortMap.lastKey()); // 判断目标应用进程是否存活 boolean isProcessAlive = false; List<ActivityManager.RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses(); if (runningProcesses != null) { for (ActivityManager.RunningAppProcessInfo info : runningProcesses) { for (String pkg : info.pkgList) { if (TextUtils.equals(pkg, packageName)) { isProcessAlive = true; break; } } if (isProcessAlive) break; } } // 进程存活且当前栈顶不是目标应用,判定为后台运行 if (isProcessAlive && !TextUtils.equals(topTask.getPackageName(), packageName)) { isBackgroundRunning = true; } } // 遍历完成后统一弹提示,避免重复弹窗 if (isBackgroundRunning) { Toast.makeText(this, "App is Running", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "App is not running", Toast.LENGTH_LONG).show(); } return isBackgroundRunning; }
关键注意点
- Android 5.0以上版本使用
UsageStatsManager接口时,需要用户手动在「设置-应用-特殊权限-使用情况访问」中为当前应用开启权限,否则无法获取应用运行数据 - 不要在遍历进程/任务的循环中弹出Toast,否则会因为遍历到多个非目标应用出现连续弹窗的异常
- 不要使用已废弃的
getRunningTasks()接口做高版本适配,该接口在Android 5.0以上只会返回当前应用自身的任务信息,无法检测第三方应用状态 - 部分深度定制的国产ROM可能对后台进程管控有特殊逻辑,需要根据实际机型做针对性适配
内容的提问来源于stack exchange,提问作者Adi
相关产品推荐
相关产品推荐

