Как узнать, работает ли Android-приложение на переднем плане?

Я делаю уведомление в строке состояния в моем приложении Android, которое запускается c2dm. Я не хочу отображать уведомление, если приложение запущено. Как вы определяете, работает ли приложение и находится ли он на переднем плане?

Solutions Collecting From Web of "Как узнать, работает ли Android-приложение на переднем плане?"

Сделать глобальную переменную, например private boolean mIsInForegroundMode; И назначить false значение в onPause() и true значение в onResume() .

Образец кода:

 private boolean mIsInForegroundMode; @Override protected void onPause() { super.onPause(); mIsInForegroundMode = false; } @Override protected void onResume() { super.onResume(); mIsInForegroundMode = true; } // Some function. public boolean isInForeground() { return mIsInForegroundMode; } 

В качестве альтернативы вы можете проверить с ActivityManager какие задачи выполняются методом getRunningTasks . Затем проверьте с первой задачей (задача на переднем плане) в возвращаемом списке задач, если это ваша задача.
Вот пример кода:

 public Notification buildNotification(String arg0, Map<String, String> arg1) { ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> services = activityManager .getRunningTasks(Integer.MAX_VALUE); boolean isActivityFound = false; if (services.get(0).topActivity.getPackageName().toString() .equalsIgnoreCase(appContext.getPackageName().toString())) { isActivityFound = true; } if (isActivityFound) { return null; } else { // write your code to build a notification. // return the notification you built here } } 

И не забудьте добавить разрешение GET_TASKS в файл manifest.xml , чтобы иметь возможность запустить getRunningTasks() в приведенном выше коде:

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

P / s: Если вы согласны с этим, обратите внимание, что это разрешение теперь устарело.

Это довольно старый пост, но все же весьма актуальный. Вышеприведенное решение может работать, но не так. Как пишет Dianne Hackborn:

Эти API не существуют для приложений, на которых основывается их поток пользовательского интерфейса, но чтобы делать такие вещи, как показывать пользователям запущенные приложения или диспетчер задач или тому подобное.

Да, есть список, хранящийся в памяти для этих вещей. Тем не менее, он отключен в другом процессе, управляемом потоками, выполняемыми отдельно от вашего, а не тем, на что вы можете рассчитывать (a) своевременно видеть правильное решение или (b) иметь согласованное изображение к моменту вашего возвращения. Кроме того, решение о том, что нужно делать «следующей» активности, всегда выполняется в точке, где должен произойти переход, и только до этой точки (где состояние активности ненадолго заблокировано, чтобы сделать переключатель), что мы На самом деле знаю, что будет следующим.

И реализация и глобальное поведение здесь не гарантируются в будущем.

Правильное решение – реализовать: ActivityLifeCycleCallbacks .

Это в основном требует класса приложений, и обработчик может быть установлен там, чтобы определить состояние ваших действий в приложении.

Как говорит Винай, возможно, лучшим решением (для поддержки новых версий Android версии 14+) является использование ActivityLifecycleCallbacks в реализации класса Application .

 package com.telcel.contenedor.appdelegate; import android.app.Activity; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; /** Determines global app lifecycle states. * * The following is the reference of activities states: * * The <b>visible</b> lifetime of an activity happens between a call to onStart() * until a corresponding call to onStop(). During this time the user can see the * activity on-screen, though it may not be in the foreground and interacting with * the user. The onStart() and onStop() methods can be called multiple times, as * the activity becomes visible and hidden to the user. * * The <b>foreground</b> lifetime of an activity happens between a call to onResume() * until a corresponding call to onPause(). During this time the activity is in front * of all other activities and interacting with the user. An activity can frequently * go between the resumed and paused states -- for example when the device goes to * sleep, when an activity result is delivered, when a new intent is delivered -- * so the code in these methods should be fairly lightweight. * * */ public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks { /** Manages the state of opened vs closed activities, should be 0 or 1. * It will be 2 if this value is checked between activity B onStart() and * activity A onStop(). * It could be greater if the top activities are not fullscreen or have * transparent backgrounds. */ private static int visibleActivityCount = 0; /** Manages the state of opened vs closed activities, should be 0 or 1 * because only one can be in foreground at a time. It will be 2 if this * value is checked between activity B onResume() and activity A onPause(). */ private static int foregroundActivityCount = 0; /** Returns true if app has foreground */ public static boolean isAppInForeground(){ return foregroundActivityCount > 0; } /** Returns true if any activity of app is visible (or device is sleep when * an activity was visible) */ public static boolean isAppVisible(){ return visibleActivityCount > 0; } public void onActivityCreated(Activity activity, Bundle bundle) { } public void onActivityDestroyed(Activity activity) { } public void onActivityResumed(Activity activity) { foregroundActivityCount ++; } public void onActivityPaused(Activity activity) { foregroundActivityCount --; } public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } public void onActivityStarted(Activity activity) { visibleActivityCount ++; } public void onActivityStopped(Activity activity) { visibleActivityCount --; } } 

И в применении onCreate() :

 registerActivityLifecycleCallbacks(new ApplicationLifecycleManager()); 

Затем ApplicationLifecycleManager.isAppVisible() или ApplicationLifecycleManager.isAppInForeground() будет использоваться для определения желаемого состояния.

FYI, если вы используете решение Gadenkan (это здорово !!), не забудьте добавить

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

К манифесту.

Немного очищенная версия решения Gadenkan . Поместите это любое действие или, возможно, базовый класс для всех ваших действий.

 protected boolean isRunningInForeground() { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1); if (tasks.isEmpty()) { return false; } String topActivityName = tasks.get(0).topActivity.getPackageName(); return topActivityName.equalsIgnoreCase(getPackageName()); } 

Чтобы иметь возможность вызвать getRunningTasks() , вам нужно добавить это в свой AndroidManifest.xml :

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

Обратите внимание, что ActivityManager.getRunningTasks() Javadoc говорит:

Примечание. Этот метод предназначен только для отладки и представления пользовательских интерфейсов управления задачами. Это никогда не должно использоваться для основной логики в приложении, например, для решения разных видов поведения на основе информации, найденной здесь. Такие виды использования не поддерживаются и, скорее всего, будут разрушены в будущем.

Обновление (февраль 2015 г.)

Обратите внимание, что getRunningTasks() устарел на уровне API 21 !

Что LOLLIPOP , этот метод больше не доступен для сторонних приложений: введение LOLLIPOP , ориентированных на документ, означает, что он может передавать информацию об абоненте вызывающей стороне. Для обратной совместимости он все равно вернет небольшое подмножество своих данных: по крайней мере, собственные задачи вызывающего абонента и, возможно, некоторые другие задачи, например, дома, которые, как известно, не чувствительны.

Итак, то, что я написал ранее, еще более актуально:

Во многих случаях вы, вероятно, можете найти лучшее решение. Например, что-то делать в onPause() и onResume() , возможно, в BaseActivity для всех ваших действий.

(В нашем случае мы не хотели запускать оффлайн-предупреждение, если мы не находимся на переднем плане, поэтому в BaseActivity onPause() мы просто отписываемся от подписки RxJava, прослушивая сигнал «off offline»).

Следуя за ответом Гаденкана, мне нужно было что-то вроде этого, чтобы я мог определить, не работает ли мое приложение на переднем плане, но мне нужно было что-то, что было достаточно для приложения, и не требовало, чтобы я устанавливал / снимал флаги во всем приложении.

Код Gadenkan в значительной степени ударил ноготь по голове, но он не был в моем собственном стиле и чувствовал, что это может быть более аккуратным, поэтому в моем приложении его сгустили до этого.

 if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName())) { // App is not in the foreground } 

(Боковое примечание: вы можете просто удалить!, Если вы хотите, чтобы чек работал по-другому)

Хотя при таком подходе вам нужно разрешение GET_TASKS .

Начиная с API 16 вы можете сделать это следующим образом:

 static boolean shouldShowNotification(Context context) { RunningAppProcessInfo myProcess = new RunningAppProcessInfo(); ActivityManager.getMyMemoryState(myProcess); if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return true; KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); // app is in foreground, but if screen is locked show notification anyway return km.inKeyguardRestrictedInputMode(); } 

Я хотел бы добавить, что более безопасный способ сделать это – чем проверка того, что ваше приложение находится в фоновом режиме перед созданием уведомления, – это просто отключить и включить широковещательный приемник onPause () и onResume () соответственно.

Этот метод дает вам больше контроля в реальной логике приложения и вряд ли изменится в будущем.

 @Override protected void onPause() { unregisterReceiver(mHandleMessageReceiver); super.onPause(); } @Override protected void onResume() { super.onResume(); registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION)); } 

Я нашел более простой и точный способ проверить, находится ли приложение на переднем плане или в фоновом режиме, сопоставляя действия с булевыми.

Проверьте полный смысл здесь

Это полезно только тогда, когда вы хотите выполнить какое-либо действие только тогда, когда начинается ваша активность, и где вы хотите проверить, находится ли приложение на переднем плане или на заднем плане.

Вместо использования Менеджера активности есть простой трюк, который вы можете сделать с помощью кода. Если вы внимательно наблюдаете за циклом активности, поток между двумя действиями и передним фоном выглядит следующим образом. Предположим, что A и B являются двумя видами деятельности.

Когда переход от A к B: 1. onPause () A называется 2. onResume () of B называется 3. onStop () of A вызывается, когда B полностью возобновляется

Когда приложение переходит в фоновый режим: 1. onPause () из A называется 2. onStop () из A называется

Вы можете обнаружить свое фоновое событие, просто поместив флаг в действие.

Сделайте абстрактную деятельность и расширьте ее от других действий, так что вам не придется копировать код для всех других действий везде, где вам нужно фоновое событие.

В абстрактной активности создайте флаг isAppInBackground.

В методе onCreate (): isAppInBackground = false;

В методе onPause (): isAppInBackground = false;

В методе onStop (): isAppInBackground = true;

Вам просто нужно проверить свой onResume (), если isAppInBackground – это правда. N после того, как вы проверите свой флаг, затем снова установите isAppInBackground = false

Для перехода между двумя действиями, так как onSTop () первой всегда будет вызываться после возобновления второго действия, флаг никогда не будет правдой, а когда приложение будет в фоновом режиме, onStop () будет вызываться сразу после onPause, и, следовательно, флаг будет true, когда Вы откроете приложение позже.

В этом подходе есть еще один сценарий. Если какой-либо экран вашего приложения уже открыт, и вы положили мобильный простоя, то через некоторое время мобильный телефон перейдет в спящий режим, и когда вы разблокируете мобильный телефон, он будет обработан при фоновом событии.

Основываясь на различных ответах и ​​комментариях, вот более инлайн-версия, которую вы можете добавить к вспомогательному классу:

 public static boolean isAppInForeground(Context context) { List<RunningTaskInfo> task = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)) .getRunningTasks(1); if (task.isEmpty()) { return false; } return task .get(0) .topActivity .getPackageName() .equalsIgnoreCase(context.getPackageName()); } 

Как уже упоминалось в других ответах, вам необходимо добавить следующее разрешение на ваш AndroidManifest.xml .

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

Вот метод, который я использую (и поддерживающий метод):

 private boolean checkIfAppIsRunningInForeground() { ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) { if(appProcessInfo.processName.contains(this.getPackageName())) { return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance); } } return false; } private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) { switch (appImportance) { //user is aware of app case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE: return true; //user is not aware of app case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE: default: return false; } } 

Предыдущие подходы, упомянутые здесь, не являются оптимальными. Для подхода, основанного на задаче, требуется разрешение, которое может быть нежелательно, и подход «Boolean» склонен к одновременным изменениям беспорядков.

Подход, который я использую и который (я считаю) работает довольно хорошо в большинстве случаев:

Имейте класс «MainApplication» для отслеживания количества операций в AtomicInteger :

 import android.app.Application; import java.util.concurrent.atomic.AtomicInteger; public class MainApplication extends Application { static class ActivityCounter { private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0); public static boolean isAppActive() { return ACTIVITY_COUNT.get() > 0; } public static void activityStarted() { ACTIVITY_COUNT.incrementAndGet(); } public static void activityStopped() { ACTIVITY_COUNT.decrementAndGet(); } } } 

Создайте базовый класс активности, который расширит другие действия:

 import android.app.Activity; import android.support.annotation.CallSuper; public class TestActivity extends Activity { @Override @CallSuper protected void onStart() { MainApplication.ActivityCounter.activityStarted(); super.onStart(); } @Override @CallSuper protected void onStop() { MainApplication.ActivityCounter.activityStopped(); super.onStop(); } } 

Глобального обратного вызова для этого нет, но для каждого действия это onStop (). Вам не нужно связываться с атомарным int. Просто используйте глобальный int с количеством запущенных действий, в каждом действии увеличивайте его в onStart () и уменьшите его на onStop ().

Следуйте этому

Вот код для простого простого решения, описанного выше, пользователем @ user2690455. Хотя это выглядит немного подробным, вы увидите, что в целом это довольно легкий

В моем случае мы также используем AppCompatActivity, поэтому мне пришлось иметь 2 базовых класса.

 public class BaseActivity extends Activity { /** * Let field be set only in base class * All callers must use accessors, * and then it's not up to them to manage state. * * Making it static since .. * 1. It needs to be used across two base classes * 2. It's a singleton state in the app */ private static boolean IS_APP_IN_BACKGROUND = false; @Override protected void onResume() { super.onResume(); BaseActivity.onResumeAppTracking(this); BaseActivity.setAppInBackgroundFalse(); } @Override protected void onStop() { super.onStop(); BaseActivity.setAppInBackgroundTrue(); } @Override protected void onPause() { super.onPause(); BaseActivity.setAppInBackgroundFalse(); } protected static void onResumeAppTracking(Activity activity) { if (BaseActivity.isAppInBackground()) { // do requirements for returning app to foreground } } protected static void setAppInBackgroundFalse() { IS_APP_IN_BACKGROUND = false; } protected static void setAppInBackgroundTrue() { IS_APP_IN_BACKGROUND = true; } protected static boolean isAppInBackground() { return IS_APP_IN_BACKGROUND; } } 
  public static boolean isAppRunning(Context context) { // check with the first task(task in the foreground) // in the returned list of tasks ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE); if (services.get(0).topActivity.getPackageName().toString().equalsIgnoreCase(context.getPackageName().toString())) { return true; } return false; }