2010-01-30 106 views
87

我希望在后台运行一个应用程序,该应用程序知道任何内置应用程序(消息传递,联系人等)何时运行。从后台任务或服务确定当前的前台应用程序

所以我的问题是:

  1. 我应该如何运行我在后台的应用程序。

  2. 我的后台应用程序如何知道当前在前台运行的应用程序是什么。

有经验的人的反应将不胜感激。

+0

我不认为你已经给出了你想要做的事情的充分解释。 *你的后台应用程序试图做什么?它应该以什么方式与用户进行交互? *为什么*你需要知道当前的前台应用程序是什么?等 – 2010-01-30 05:30:56

+0

http://codingaffairs.blogspot.com/2016/05/check-if-your-android-app-is-in.html – 2016-05-25 03:39:10

+1

为检测前台应用程序,您可以使用https://github.com/ ricvalerio/foregroundappchecker – rvalerio 2016-08-28 22:57:33

回答

7

ActivityManager类是查看哪些进程正在运行的适当工具。

要在后台运行,通常需要使用Service

0

做这样的事情:

int showLimit = 20; 

/* Get all Tasks available (with limit set). */ 
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit); 
/* Loop through all tasks returned. */ 
for (ActivityManager.RunningTaskInfo aTask : allTasks) 
{     
    Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName()); 
    if (aTask.baseActivity.getClassName().equals("com.android.email.activity.MessageList")) 
     running=true; 
} 
+0

Google可能会拒绝使用ActivityManager.getRunningTasks()的应用程序。该文档声明它仅用于开发目的:http://developer.android.com/reference/android/app/ActivityManager.html#getRunningTasks%28int%29请参阅初始评论: http://stackoverflow.com/问题/ 4414171/how-to-detect-when-an-android-app-goes-the-background-and-come-back-to-fo#comment16801122_9876683 – ForceMagic 2014-01-14 21:44:38

+2

@ForceMagic - Google不会仅仅拒绝应用程序使用*不可靠的API;此外,Google不是Android应用程序的唯一分销渠道。也就是说,值得记住的是,来自这个API的信息是不可靠的。 – 2014-05-27 19:53:32

+0

@ChrisStratton有趣的,但你可能是对的,尽管不愿意将它用于核心逻辑,但他们不会拒绝应用程序。您可能需要从评论链接警告Sky Kelsey。 – ForceMagic 2014-05-27 20:18:13

28

试试下面的代码:

ActivityManager activityManager = (ActivityManager) newContext.getSystemService(Context.ACTIVITY_SERVICE); 
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); 
for(RunningAppProcessInfo appProcess : appProcesses){ 
    if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){ 
     Log.i("Foreground App", appProcess.processName); 
    } 
} 

进程名是在前台运行的应用的应用包名称。将其与您的应用程序的软件包名称进行比较。如果它是相同的,那么你的应用程序在前台运行。

我希望这能回答你的问题。

+6

从Android版本起,这是唯一的解决方案如果在其他解决方案中使用的方法已经被弃用 – androidGuy 2014-11-20 09:20:55

+2

但是,在应用程序处于前台并且屏幕锁定的情况下,这不起作用 – Krit 2015-07-18 10:35:36

+0

正确答案 应勾选 – 2016-03-23 04:04:33

37

我不得不以困难的方式找出正确的解决方案。下面的代码是cyanogenmod7(平板电脑调整)的一部分,并在Android 2.3.3 /姜饼上测试。

方法:

  • getForegroundApp - 返回前台应用程序。
  • getActivityForApp - 返回找到的应用程序的活动。
  • isStillActive - 确定先前发现的应用程序是否仍然是活动应用程序。
  • isRunningService - 为getForegroundApp

一个辅助函数,这个希望回答了这个问题都可以扩展(:

private RunningAppProcessInfo getForegroundApp() { 
    RunningAppProcessInfo result=null, info=null; 

    if(mActivityManager==null) 
     mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); 
    List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses(); 
    Iterator <RunningAppProcessInfo> i = l.iterator(); 
    while(i.hasNext()){ 
     info = i.next(); 
     if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND 
       && !isRunningService(info.processName)){ 
      result=info; 
      break; 
     } 
    } 
    return result; 
} 

private ComponentName getActivityForApp(RunningAppProcessInfo target){ 
    ComponentName result=null; 
    ActivityManager.RunningTaskInfo info; 

    if(target==null) 
     return null; 

    if(mActivityManager==null) 
     mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); 
    List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999); 
    Iterator <ActivityManager.RunningTaskInfo> i = l.iterator(); 

    while(i.hasNext()){ 
     info=i.next(); 
     if(info.baseActivity.getPackageName().equals(target.processName)){ 
      result=info.topActivity; 
      break; 
     } 
    } 

    return result; 
} 

private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity) 
{ 
    // activity can be null in cases, where one app starts another. for example, astro 
    // starting rock player when a move file was clicked. we dont have an activity then, 
    // but the package exits as soon as back is hit. so we can ignore the activity 
    // in this case 
    if(process==null) 
     return false; 

    RunningAppProcessInfo currentFg=getForegroundApp(); 
    ComponentName currentActivity=getActivityForApp(currentFg); 

    if(currentFg!=null && currentFg.processName.equals(process.processName) && 
      (activity==null || currentActivity.compareTo(activity)==0)) 
     return true; 

    Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: " 
      + (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString()) 
      + " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString())); 
    return false; 
} 

private boolean isRunningService(String processname){ 
    if(processname==null || processname.isEmpty()) 
     return false; 

    RunningServiceInfo service; 

    if(mActivityManager==null) 
     mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); 
    List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999); 
    Iterator <RunningServiceInfo> i = l.iterator(); 
    while(i.hasNext()){ 
     service = i.next(); 
     if(service.process.equals(processname)) 
      return true; 
    } 

    return false; 
} 
+0

如果您不介意问我,为什么您需要方法来查看它是否正在运行服务,是否仍处于活动状态,并且仅获取前台应用程序的活动 – 2011-06-13 19:49:53

+2

对不起,但它不工作,有些应用程序是filtere d没有理由,我想这是他们运行一些服务的时候。所以isRunningService正在踢出它。 – seb 2012-08-18 10:46:41

+13

不幸的是,自Android L(API 20)以来,getRunningTasks()已被弃用。 从L起,此方法不再适用于第三方应用程序:引入以文档为中心的最近值意味着它可能会将个人信息泄漏给调用者。为了向后兼容,它仍然会返回一小部分数据:至少是调用者自己的任务,还有可能是一些其他任务,比如家中已知不敏感的任务。 – 2014-06-29 06:11:09

97

至于“2.如何我的后台应用可以知道应用程序正在运行什么在前景是“。

不要使用getRunningAppProcesses()方法,因为这从我的经验返回各种系统垃圾,你会得到多个结果有RunningAppProcessInfo.IMPORTANCE_FOREGROUND。使用getRunningTasks()代替

这是代码我在服务中使用,以确定当前的前台应用程序,它真的很简单:

ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE); 
// The first in the list of RunningTasks is always the foreground task. 
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); 

完蛋了,那么你就可以轻松地访问前台应用程序/活动详情:

String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName(); 
PackageManager pm = AppService.this.getPackageManager(); 
PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0); 
String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString(); 

这需要活动清单中的额外权限并且完美地工作。

<uses-permission android:name="android.permission.GET_TASKS" /> 
+3

好多了,谢谢! – gilm 2013-02-11 10:05:55

+0

这应该被标记为正确的答案。必需的权限:android.permission.GET_TASKS是其他方法可以避免的唯一很小的缺点。 – brandall 2013-03-04 19:24:32

+3

对上述内容进行编辑:注意:此方法仅用于调试和显示任务管理用户界面。 < - 刚刚发现在Java文档中。所以这种方法在未来可能会改变,恕不另行通知。 – brandall 2013-03-04 19:31:37

0

这对我有效。但它只给出主菜单名称。这就是说,如果用户已经打开设置 - >蓝牙 - >设备名称屏幕,则RunningAppProcessInfo将其称为设置。不能深入挖掘

ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
       PackageManager pm = context.getPackageManager(); 
       List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); 
       for(RunningAppProcessInfo appProcess : appProcesses) {    
        if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { 
         CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA)); 
         Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString()); 
        }    
       } 
21

从棒棒糖开始,这已经发生了变化。请从下面的代码,在此之前,用户必须去设置 - >安全 - >(向下滚动到最后一个)与使用权限的应用程序 - >给的权限,以我们的应用程序

private void printForegroundTask() { 
    String currentApp = "NULL"; 
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { 
     UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE); 
     long time = System.currentTimeMillis(); 
     List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); 
     if (appList != null && appList.size() > 0) { 
      SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>(); 
      for (UsageStats usageStats : appList) { 
       mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); 
      } 
      if (mySortedMap != null && !mySortedMap.isEmpty()) { 
       currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); 
      } 
     } 
    } else { 
     ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); 
     List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses(); 
     currentApp = tasks.get(0).processName; 
    } 

    Log.e(TAG, "Current App in foreground is: " + currentApp); 
} 
+1

着这种使用状态进行编程设置假的? – rubmz 2015-07-26 12:12:39

+0

@rubmz你有任何这解决方案? – VVB 2016-01-23 18:12:55

+0

是现在添加的答案在我的道格 – rubmz 2016-01-24 05:54:05

0

在棒棒糖和高达:

添加到mainfest:

<uses-permission android:name="android.permission.GET_TASKS" /> 

,做这样的事情:

if(mTaskId < 0) 
{ 
    List<AppTask> tasks = mActivityManager.getAppTasks(); 
    if(tasks.size() > 0) 
     mTaskId = tasks.get(0).getTaskInfo().id; 
} 
+3

它已经过时成棉花糖 – jinkal 2016-01-24 06:18:51

0

这是豪w我正在检查我的应用程序是否在前台。请注意,我用的AsyncTask官方的Android的建议documentation.`

`

private class CheckIfForeground extends AsyncTask<Void, Void, Void> { 
    @Override 
    protected Void doInBackground(Void... voids) { 

     ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 
     List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); 
     for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { 
      if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { 
       Log.i("Foreground App", appProcess.processName); 

       if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) { 
        Log.i(Constants.TAG, "foreground true:" + appProcess.processName); 
        foreground = true; 
        // close_app(); 
       } 
      } 
     } 
     Log.d(Constants.TAG, "foreground value:" + foreground); 
     if (foreground) { 
      foreground = false; 
      close_app(); 
      Log.i(Constants.TAG, "Close App and start Activity:"); 

     } else { 
      //if not foreground 
      close_app(); 
      foreground = false; 
      Log.i(Constants.TAG, "Close App"); 

     } 

     return null; 
    } 
} 

和执行的AsyncTask这样。 new CheckIfForeground().execute();

+0

你有一个链接呢? – user1743524 2016-07-28 20:59:18

3

为了确定前台应用程序,您可以使用它来检测前台应用程序,您可以使用https://github.com/ricvalerio/foregroundappchecker。它根据设备的android版本使用不同的方法。

至于服务,回购也提供了你需要它的代码。本质上,让android studio为你创建服务,然后onCreate添加使用appChecker的代码片段。但是,您需要请求权限。

5

考虑到getRunningTasks()已被弃用,getRunningAppProcesses()是不可靠的,我来到了一个解决方案,在StackOverflow上提到的2种方法结合起来:

private boolean isAppInForeground(Context context) 
    { 
     if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) 
     { 
      ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); 
      ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); 
      String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName(); 

      return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase()); 
     } 
     else 
     { 
      ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); 
      ActivityManager.getMyMemoryState(appProcessInfo); 
      if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) 
      { 
       return true; 
      } 

      KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); 
      // App is foreground, but screen is locked, so show notification 
      return km.inKeyguardRestrictedInputMode(); 
     } 
    } 
+0

你需要提及添加到清单中的过时许可<使用许可权的android:NAME =“android.permission.GET_TASKS” />否则应用程序会崩溃 – RJFares 2018-01-09 14:22:44

0

我在一个方法结合了两种解决方案,和它的作品对我来说API 24和API 21.其他我没有测试。

在科特林代码:

private fun isAppInForeground(context: Context): Boolean { 
    val appProcessInfo = ActivityManager.RunningAppProcessInfo() 
    ActivityManager.getMyMemoryState(appProcessInfo) 
    if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || 
      appProcessInfo.importance == IMPORTANCE_VISIBLE) { 
     return true 
    } else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING || 
      appProcessInfo.importance == IMPORTANCE_BACKGROUND) { 
     return false 
    } 

    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager 
    val foregroundTaskInfo = am.getRunningTasks(1)[0] 
    val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName 
    return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase() 
} 

,并在清单

<!-- Check whether app in background or foreground --> 
<uses-permission android:name="android.permission.GET_TASKS" /> 
0

对于情况下,当我们需要从我们自己的服务/后台线程来检查我们的应用程序是否在前台与否。这是我是如何实现它,它为我工作得很好:

public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks { 

    public static WeakReference<Activity> foregroundActivityRef = null; 

    @Override 
    public void onActivityStarted(Activity activity) { 
     foregroundActivityRef = new WeakReference<>(activity); 
    } 

    @Override 
    public void onActivityStopped(Activity activity) { 
     if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) { 
      foregroundActivityRef = null; 
     } 
    } 

    // IMPLEMENT OTHER CALLBACK METHODS 
} 

我们从其他类检查,应用程序是否在前台与否,只需拨打:

if(TestApplication.foregroundActivityRef!=null){ 
    // APP IS IN FOREGROUND! 
    // We can also get the activity that is currently visible! 
} 
相关问题