2010-01-30 103 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! 
} 
相關問題