Как определить, когда приложение Android переходит на задний план и возвращается на передний план

Я пытаюсь написать приложение, которое делает что-то конкретное, когда оно возвращается на передний план через некоторое время. Есть ли способ обнаружить, когда приложение отправлено на задний план или выведено на передний план?

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

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

Подробнее см. Здесь. Android: решение для обнаружения, когда приложение Android переходит на задний план и возвращается на передний план без getRunningTasks или getRunningAppProcesses .

Вот как мне удалось это решить. Он работает исходя из предпосылки, что использование временной привязки между переходами активности, скорее всего, даст достаточные доказательства того, что приложение было «запрошено» или нет.

Во-первых, я использовал экземпляр android.app.Application (назовем его MyApplication), у которого есть Timer, TimerTask, константа, представляющая максимальное количество миллисекунд, которое может разумно принять переход от одного действия к другому (я пошел со значением 2s) и логическое значение, указывающее, было ли приложение «в фоновом режиме»:

 public class MyApplication extends Application { private Timer mActivityTransitionTimer; private TimerTask mActivityTransitionTimerTask; public boolean wasInBackground; private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000; ... 

Приложение также предоставляет два способа запуска и остановки таймера / задачи:

 public void startActivityTransitionTimer() { this.mActivityTransitionTimer = new Timer(); this.mActivityTransitionTimerTask = new TimerTask() { public void run() { MyApplication.this.wasInBackground = true; } }; this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask, MAX_ACTIVITY_TRANSITION_TIME_MS); } public void stopActivityTransitionTimer() { if (this.mActivityTransitionTimerTask != null) { this.mActivityTransitionTimerTask.cancel(); } if (this.mActivityTransitionTimer != null) { this.mActivityTransitionTimer.cancel(); } this.wasInBackground = false; } 

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

 @Override public void onResume() { super.onResume(); MyApplication myApp = (MyApplication)this.getApplication(); if (myApp.wasInBackground) { //Do specific came-here-from-background code } myApp.stopActivityTransitionTimer(); } @Override public void onPause() { super.onPause(); ((MyApplication)this.getApplication()).startActivityTransitionTimer(); } 

Таким образом, в случае, когда пользователь просто перемещается между действиями вашего приложения, onPause () отходящей активности запускает таймер, но почти сразу вводимая новая активность отменяет таймер до достижения максимального времени перехода. И так wasInBackground будет ложным .

С другой стороны, когда на переднем плане запускается Activity с Launcher, устройство просыпается, завершает телефонный звонок и т. Д., Более чем вероятно, задача таймера, выполненная до этого события, и, таким образом, wasInBackground был установлен в true .

2018: Android поддерживает эту функцию через компоненты жизненного цикла.

Март 2018 ОБНОВЛЕНИЕ : теперь есть лучшее решение. См. ProcessLifecycleOwner . Вам нужно будет использовать новые компоненты архитектуры 1.1.0 (последние в это время), но это специально предназначено для этого.

В этом ответе есть простой пример, но я написал пример приложения и сообщение в блоге об этом.

С тех пор, как я написал это еще в 2014 году, возникли различные решения. Некоторые работали, некоторые считались работающими , но имели недостатки (включая мой!), И мы, как сообщество (Android) научились жить с последствиями и писали обходные пути для особых случаев.

Никогда не предполагайте, что один fragment кода – это решение, которое вы ищете, маловероятно; еще лучше, попытайтесь понять, что он делает и почему он это делает.

Класс MemoryBoss никогда не использовался мной, как написано здесь, это был всего лишь fragment псевдокода, который работал.

Если у вас нет веских оснований для того, чтобы вы не использовали новые компоненты архитектуры (и есть некоторые, особенно если вы нацелились на сверхбыстрый apis), тогда идите и используйте их. Они далеки от совершенства, но не были ComponentCallbacks2 .

ОБНОВЛЕНИЕ / ПРИМЕЧАНИЯ (ноябрь 2015 г.) : люди делали два комментария: сначала следует использовать >= вместо == потому что в документации указано, что вы не должны проверять точные значения . Это нормально для большинства случаев, но имейте в виду, что если вы только заботитесь о том, чтобы что-то делать, когда приложение переходило на задний план, вам придется использовать ==, а также объединить его с другим решением (например, обратными вызовами Activity Lifecycle), или вы может не получить желаемого эффекта. Пример (и это случилось со мной) заключается в том, что если вы хотите заблокировать свое приложение с помощью экрана пароля, когда он идет на задний план (например, 1Password, если вы знакомы с ним), вы можете случайно заблокировать свое приложение, на память и внезапно тестируются на >= TRIM_MEMORY , потому что Android вызовет вызов LOW MEMORY и это выше вашего. Поэтому будьте осторожны, как и что вы тестируете.

Кроме того, некоторые люди спрашивают о том, как определить, когда вы вернетесь.

Самый простой способ, о котором я могу думать, объясняется ниже, но, поскольку некоторые люди не знакомы с ним, я добавляю несколько псевдо-кода прямо здесь. Предполагая, что у вас есть YourApplication и MemoryBoss , в вашем class BaseActivity extends Activity (вам нужно будет создать его, если у вас его нет).

 @Override protected void onStart() { super.onStart(); if (mApplication.wasInBackground()) { // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND mApplication.setWasInBackground(false); } } 

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

И это все. Код в блоке if будет выполняться только один раз , даже если вы перейдете к другому действию, новый (который также extends BaseActivity ) сообщит, что wasInBackground имеет значение false поэтому он не будет выполнять код, пока не onMemoryTrimmed а флаг снова установлено значение true .

Надеюсь, это поможет.

UPDATE / NOTES (апрель 2015 г.) : перед тем, как вы перейдете ко всем копиям и вставить в этот код, обратите внимание, что я нашел несколько примеров, где он может быть не на 100% надежным и должен быть объединен с другими методами для достижения наилучших результатов. Примечательно, что существуют два известных случая, когда вызов onTrimMemory не гарантируется для выполнения:

  1. Если ваш телефон блокирует экран во время видимости вашего приложения (например, ваше устройство блокируется через nn минут), этот обратный вызов не вызывается (или не всегда), потому что блокировка экрана находится сверху, но ваше приложение все еще работает, хотя и закрыто.

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

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

Просто держите это в уме и получите хорошую команду QA;)

КОНЕЦ ОБНОВЛЕНИЯ

Это может быть поздно, но есть надежный метод в Ice Cream Sandwich (API 14) и выше .

Оказывается, когда ваше приложение не имеет более видимого интерфейса, срабатывает обратный вызов. Обратный вызов, который вы можете реализовать в пользовательском classе, называется ComponentCallbacks2 (да, с двумя). Этот обратный вызов доступен только в API Level 14 (Ice Cream Sandwich) и выше.

Вы в основном получаете вызов метода:

 public abstract void onTrimMemory (int level) 

Уровень 20 или более конкретно

 public static final int TRIM_MEMORY_UI_HIDDEN 

Я тестировал это, и он всегда работает, потому что 20-й уровень – это всего лишь «предложение», что вы можете захотеть освободить некоторые ресурсы, поскольку ваше приложение больше не видно.

Процитировать официальные документы:

Уровень для onTrimMemory (int): процесс показывал пользовательский интерфейс и больше не делает этого. Большие распределения с пользовательским интерфейсом должны быть выпущены в этот момент, чтобы обеспечить лучшую управляемость памяти.

Конечно, вы должны реализовать это, чтобы на самом деле делать то, что он говорит (очистить память, которая не использовалась в определенное время, очистить некоторые коллекции, которые сидят неиспользованными, и т. Д. Возможности бесконечны (см. Официальные документы для других возможных более критические уровни).

Но интересно, что ОС говорит вам: ЭЙ, ваше приложение ушло на задний план!

Это именно то, что вы хотели знать в первую очередь.

Как вы определяете, когда вернетесь?

Ну, это легко, я уверен, что у вас есть «BaseActivity», поэтому вы можете использовать свой onResume (), чтобы отметить тот факт, что вы вернулись. Потому что единственный раз, когда вы будете говорить, что вы не вернулись, когда вы на самом деле получаете вызов вышеуказанного метода onTrimMemory .

Оно работает. Вы не получаете ложных срабатываний. Если действие возобновляется, вы вернетесь в 100% случаев. Если пользователь снова возвращается к вам, вы получаете еще один onTrimMemory() .

Вам нужно подписать свои действия (или, еще лучше, пользовательский class).

Самый простой способ гарантировать, что вы всегда получаете это, – создать простой class следующим образом:

 public class MemoryBoss implements ComponentCallbacks2 { @Override public void onConfigurationChanged(final Configuration newConfig) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // We're in the Background } // you might as well implement some memory cleanup here and be a nice Android dev. } } 

Чтобы использовать это, в вашей реализации приложения (у вас есть один, ПРАВО? ), Сделайте что-то вроде:

 MemoryBoss mMemoryBoss; @Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mMemoryBoss = new MemoryBoss(); registerComponentCallbacks(mMemoryBoss); } } 

Если вы создаете Interface вы можете добавить к нему else значение if и реализовать ComponentCallbacks (без 2), используемого в чем-либо ниже API 14. Этот обратный вызов имеет только метод onLowMemory() и не вызывается при onLowMemory() на задний план , но вы должны использовать его для обрезки памяти.

Теперь запустите приложение и нажмите домой. Необходимо называть метод onTrimMemory(final int level) (подсказка: добавить журнал).

Последний шаг – отменить регистрацию из обратного вызова. Вероятно, лучшим местом является метод onTerminate() вашего приложения, но этот метод не вызывается на реальном устройстве:

 /** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */ 

Поэтому, если у вас действительно нет ситуации, когда вы больше не хотите регистрироваться, вы можете ее игнорировать, поскольку ваш процесс все равно умирает на уровне ОС.

Если вы решите в какой-то момент отменить регистрацию (если вы, например, предоставляете механизм отключения вашего приложения для очистки и смерти), вы можете сделать следующее:

 unregisterComponentCallbacks(mMemoryBoss); 

Вот и все.

Изменить: новые компоненты архитектуры принесли что-то многообещающее: ProcessLifecycleOwner , см . Ответ @ vokilam


Фактическое решение согласно разговору ввода-вывода Google :

 class YourApplication : Application() { override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(AppLifecycleTracker()) } } class AppLifecycleTracker : Application.ActivityLifecycleCallbacks { private var numStarted = 0 override fun onActivityStarted(activity: Activity?) { if (numStarted == 0) { // app went to foreground } numStarted++ } override fun onActivityStopped(activity: Activity?) { numStarted-- if (numStarted == 0) { // app went to background } } } 

Да. Я знаю, что трудно поверить, что это простое решение работает, так как здесь у нас так много странных решений.

Но есть надежда.

На основании ответа Мартина Маркончиниса (спасибо!) Я наконец нашел надежное (и очень простое) решение.

 public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName(); private static boolean isInBackground = false; @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { if(isInBackground){ Log.d(TAG, "app went to foreground"); isInBackground = false; } } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(int i) { if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){ Log.d(TAG, "app went to background"); isInBackground = true; } } } 

Затем добавьте это в свой class onCreate () вашего приложения

 public class MyApp extends android.app.Application { @Override public void onCreate() { super.onCreate(); ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler(); registerActivityLifecycleCallbacks(handler); registerComponentCallbacks(handler); } } 

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

Идея заключается в том, что на переднем плане Android всегда начинает новую активность непосредственно перед тем, как останавливать предыдущую. Это не гарантировано, но так оно и работает. Кстати, Flurry, похоже, использует ту же логику (просто гадать, я не проверял это, но он перехватывает те же события).

 public abstract class BaseActivity extends Activity { private static int sessionDepth = 0; @Override protected void onStart() { super.onStart(); sessionDepth++; if(sessionDepth == 1){ //app came to foreground; } } @Override protected void onStop() { super.onStop(); if (sessionDepth > 0) sessionDepth--; if (sessionDepth == 0) { // app went to background } } } 

Изменить: согласно комментариям, мы также перешли к onStart () в более поздних версиях кода. Кроме того, я добавляю супер-вызовы, которые отсутствовали в моем первоначальном сообщении, потому что это была скорее концепция, чем рабочий код.

Если ваше приложение состоит из нескольких активных и / или многоуровневых действий, таких как виджет панели вкладок, переопределение onPause () и onResume () не будет работать. Т.е. при запуске нового действия текущая активность приостанавливается до создания нового. То же самое происходит при завершении (с использованием кнопки «назад») активности.

Я нашел два метода, которые, похоже, работают по мере необходимости.

Первый требует разрешения GET_TASKS и состоит из простого метода, который проверяет, принадлежит ли верхняя работа на устройстве к приложению, путем сравнения имен пакетов:

 private boolean isApplicationBroughtToBackground() { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List tasks = am.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; if (!topActivity.getPackageName().equals(context.getPackageName())) { return true; } } return false; } 

Этот метод был найден в структуре Droid-Fu (теперь называемой Ignition).

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

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

Когда количество запущенных действий достигает 0, приложение помещается в фоновое поле, если выполняются следующие условия:

  • Действие, приостановленное, не завершается (использовалась кнопка «назад»). Это можно сделать, используя метод activity.isFinishing ()
  • Новое действие (такое же имя пакета) не запускается. Вы можете переопределить метод startActivity (), чтобы установить переменную, которая указывает это, а затем сбросить ее в onPostResume (), который является последним методом, который будет запускаться при создании / возобновлении действия.

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

ProcessLifecycleOwner представляется перспективным решением.

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

Реализация может быть такой же простой, как

 public class AppLifecycleListener implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onMoveToForeground() { // app moved to foreground } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onMoveToBackground() { // app moved to background } } // register observer ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleListener()); 

Согласно исходному коду значение текущей задержки составляет 700ms .

Создайте class , расширяющий Application . Затем в нем мы можем использовать свой метод переопределения onTrimMemory() .

Чтобы определить, попало ли приложение в фоновый режим, мы будем использовать:

  @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity // Get called every-time when application went to background. } else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty } } 

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

Когда вызывается UserLeaveHint, вы можете установить логический флаг inBackground в значение true. Когда вызывается onResume, предположите, что вы вернулись на передний план, если установлен флаг inBackground. Это связано с тем, что onResume также будет вызываться в вашем основном действии, если пользователь был только в вашем меню настроек и никогда не покидал приложение.

Помните, что если пользователь нажимает кнопку «Дом» на экране настроек, onUserLeaveHint будет вызываться в вашей активности настроек, а когда они возвратятся, то в вашей настройке будет вызываться onResume. Если у вас есть только этот код обнаружения в вашем основном действии, вы пропустите этот вариант использования. Чтобы иметь этот код во всех ваших действиях без дублирования кода, у вас есть абстрактный class активности, который расширяет Activity и помещает в него ваш общий код. Тогда каждая ваша деятельность может расширить эту абстрактную деятельность.

Например:

 public abstract AbstractActivity extends Activity { private static boolean inBackground = false; @Override public void onResume() { if (inBackground) { // You just came from the background inBackground = false; } else { // You just returned from another activity within your own app } } @Override public void onUserLeaveHint() { inBackground = true; } } public abstract MainActivity extends AbstractActivity { ... } public abstract SettingsActivity extends AbstractActivity { ... } 

ActivityLifecycleCallbacks может представлять интерес, но он плохо документирован.

Хотя, если вы вызываете registerActivityLifecycleCallbacks (), вы должны иметь возможность получать обратные вызовы, когда создаются, уничтожаются и т. Д. Вы можете вызвать getComponentName () для Activity.

В своем приложении добавьте обратный вызов и проверьте на активность root следующим образом:

 @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityStopped(Activity activity) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) { Log.e(YourApp.TAG, "Reload defaults on restoring from background."); loadDefaults(); } } }); } 

I have created a project on Github app-foreground-background-listen

Create a BaseActivity for all Activity in your application.

 public class BaseActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } public static boolean isAppInFg = false; public static boolean isScrInFg = false; public static boolean isChangeScrFg = false; @Override protected void onStart() { if (!isAppInFg) { isAppInFg = true; isChangeScrFg = false; onAppStart(); } else { isChangeScrFg = true; } isScrInFg = true; super.onStart(); } @Override protected void onStop() { super.onStop(); if (!isScrInFg || !isChangeScrFg) { isAppInFg = false; onAppPause(); } isScrInFg = false; } public void onAppStart() { // Remove this toast Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show(); // Your code } public void onAppPause() { // Remove this toast Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show(); // Your code } } 

Now use this BaseActivity as a super class of all your Activity like MainActivity extends BaseActivity and onAppStart will be called when you start your application and onAppPause() will be called when the application goes the background from any screen.

This is pretty easy with ProcessLifecycleOwner

Add these dependencies

 implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion" kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion" 

In Kotlin :

 class ForegroundBackgroundListener : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun startSomething() { Log.v("ProcessLog", "APP IS ON FOREGROUND") } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun stopSomething() { Log.v("ProcessLog", "APP IS IN BACKGROUND") } } 

Then in your base activity:

 override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get() .lifecycle .addObserver( ForegroundBackgroundListener() .also { appObserver = it }) } 

See my article on this topic: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

I found a good method to detect application whether enter foreground or background. Here is my code . Надеюсь, это поможет вам.

 /** * Custom Application which can detect application state of whether it enter * background or enter foreground. * * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html */ public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks { public static final int STATE_UNKNOWN = 0x00; public static final int STATE_CREATED = 0x01; public static final int STATE_STARTED = 0x02; public static final int STATE_RESUMED = 0x03; public static final int STATE_PAUSED = 0x04; public static final int STATE_STOPPED = 0x05; public static final int STATE_DESTROYED = 0x06; private static final int FLAG_STATE_FOREGROUND = -1; private static final int FLAG_STATE_BACKGROUND = -2; private int mCurrentState = STATE_UNKNOWN; private int mStateFlag = FLAG_STATE_BACKGROUND; @Override public void onCreate() { super.onCreate(); mCurrentState = STATE_UNKNOWN; registerActivityLifecycleCallbacks(this); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { // mCurrentState = STATE_CREATED; } @Override public void onActivityStarted(Activity activity) { if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) { if (mStateFlag == FLAG_STATE_BACKGROUND) { applicationWillEnterForeground(); mStateFlag = FLAG_STATE_FOREGROUND; } } mCurrentState = STATE_STARTED; } @Override public void onActivityResumed(Activity activity) { mCurrentState = STATE_RESUMED; } @Override public void onActivityPaused(Activity activity) { mCurrentState = STATE_PAUSED; } @Override public void onActivityStopped(Activity activity) { mCurrentState = STATE_STOPPED; } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { mCurrentState = STATE_DESTROYED; } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) { if (mStateFlag == FLAG_STATE_FOREGROUND) { applicationDidEnterBackground(); mStateFlag = FLAG_STATE_BACKGROUND; } }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) { if (mStateFlag == FLAG_STATE_FOREGROUND) { applicationDidDestroyed(); mStateFlag = FLAG_STATE_BACKGROUND; } } } /** * The method be called when the application been destroyed. But when the * device screen off,this method will not invoked. */ protected abstract void applicationDidDestroyed(); /** * The method be called when the application enter background. But when the * device screen off,this method will not invoked. */ protected abstract void applicationDidEnterBackground(); /** * The method be called when the application enter foreground. */ protected abstract void applicationWillEnterForeground(); 

}

Edit 2: What I’ve written below will not actually work. Google has rejected an app that includes a call to ActivityManager.getRunningTasks(). From the documentation , it is apparent that this API is for debugging and development purposes only. I’ll be updating this post as soon as I have time to update the GitHub project below with a new scheme that uses timers and is almost as good.

Edit 1: I’ve written up a blog post and created a simple GitHub repository to make this really easy.

The accepted and top rated answer are both not really the best approach. The top rated answer’s implementation of isApplicationBroughtToBackground() does not handle the situation where the Application’s main Activity is yielding to an Activity that is defined in the same Application, but it has a different Java package. I came up with a way to do this that will work in that case.

Call this in onPause(), and it will tell you if your application is going into the background because another application has started, or the user has pressed the home button.

 public static boolean isApplicationBroughtToBackground(final Activity activity) { ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); List tasks = activityManager.getRunningTasks(1); // Check the top Activity against the list of Activities contained in the Application's package. if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; try { PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES); for (ActivityInfo activityInfo : pi.activities) { if(topActivity.getClassName().equals(activityInfo.name)) { return false; } } } catch( PackageManager.NameNotFoundException e) { return false; // Never happens. } } return true; } 

Вы можете использовать:

protected void onRestart ()

To differ between new starts and restarts.

введите описание изображения здесь

My solution was inspired by @d60402’s answer and also relies on a time-window, but not using the Timer :

 public abstract class BaseActivity extends ActionBarActivity { protected boolean wasInBackground = false; @Override protected void onStart() { super.onStart(); wasInBackground = getApp().isInBackground; getApp().isInBackground = false; getApp().lastForegroundTransition = System.currentTimeMillis(); } @Override protected void onStop() { super.onStop(); if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition ) getApp().isInBackground = true; } protected SingletonApplication getApp(){ return (SingletonApplication)getApplication(); } } 

where the SingletonApplication is an extension of Application class:

 public class SingletonApplication extends Application { public boolean isInBackground = false; public long lastForegroundTransition = 0; } 

I was using this with Google Analytics EasyTracker, and it worked. It could be extended to do what you seek using a simple integer.

 public class MainApplication extends Application { int isAppBackgrounded = 0; @Override public void onCreate() { super.onCreate(); appBackgroundedDetector(); } private void appBackgroundedDetector() { registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { EasyTracker.getInstance(MainApplication.this).activityStart(activity); } @Override public void onActivityResumed(Activity activity) { isAppBackgrounded++; if (isAppBackgrounded > 0) { // Do something here } } @Override public void onActivityPaused(Activity activity) { isAppBackgrounded--; } @Override public void onActivityStopped(Activity activity) { EasyTracker.getInstance(MainApplication.this).activityStop(activity); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } }); } } 

i know its a little late but i think all these answers do have some problems while i did it like below and that works perfect.

create a activity life cycle callback like this:

  class ActivityLifeCycle implements ActivityLifecycleCallbacks{ @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { } Activity lastActivity; @Override public void onActivityResumed(Activity activity) { //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time if (activity != null && activity == lastActivity) { Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show(); } lastActivity = activity; } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } } 

and just register it on your application class like below:

 public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifeCycle()); } 

This is the modified version of @d60402’s answer: https://stackoverflow.com/a/15573121/4747587

Do everything mentioned there. But instead of having a Base Activity and making that as a parent for every activity and the overriding the onResume() and onPause , do the below:

In your application class, add the line:

registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback);

This callback has all the activity lifecycle methods and you can now override onActivityResumed() and onActivityPaused() .

Take a look at this Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

What I did is make sure that all in-app activities are launched with startActivityForResult then checking if onActivityResult was called before onResume. If it wasn’t, it means we just returned from somewhere outside our app.

 boolean onActivityResultCalledBeforeOnResume; @Override public void startActivity(Intent intent) { startActivityForResult(intent, 0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); onActivityResultCalledBeforeOnResume = true; } @Override protected void onResume() { super.onResume(); if (!onActivityResultCalledBeforeOnResume) { // here, app was brought to foreground } onActivityResultCalledBeforeOnResume = false; } 

This is my solution https://github.com/doridori/AndroidUtils/blob/master/App/src/main/java/com/doridori/lib/app/ActivityCounter.java

Basically involved counting the lifecycle methods for all Activity’s with a timer to catch cases where there is no activity currently in the foreground but the app is (ie on rotation)

Вот мое решение. Just register this ActivityLifecycleCallbacks in your main Application class. In the comments, I mention a user profile Activity edge case. That Activity is simply one with transparent edges.

 /** * This class used Activity lifecycle callbacks to determine when the application goes to the * background as well as when it is brought to the foreground. */ public class Foreground implements Application.ActivityLifecycleCallbacks { /** * How long to wait before checking onStart()/onStop() count to determine if the app has been * backgrounded. */ public static final long BACKGROUND_CHECK_DELAY_MS = 500; private static Foreground sInstance; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private boolean mIsForeground = false; private int mCount; public static void init(final Application application) { if (sInstance == null) { sInstance = new Foreground(); application.registerActivityLifecycleCallbacks(sInstance); } } public static Foreground getInstance() { return sInstance; } public boolean isForeground() { return mIsForeground; } public boolean isBackground() { return !mIsForeground; } @Override public void onActivityStarted(final Activity activity) { mCount++; // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to // the app before it runs. mMainThreadHandler.removeCallbacksAndMessages(null); if (!mIsForeground) { mIsForeground = true; } } @Override public void onActivityStopped(final Activity activity) { mCount--; // A transparent Activity like community user profile won't stop the Activity that launched // it. If you launch another Activity from the user profile or hit the Android home button, // there are two onStops(). One for the user profile and one for its parent. Remove any // posted Runnables so we don't get two session ended events. mMainThreadHandler.removeCallbacksAndMessages(null); mMainThreadHandler.postDelayed(new Runnable() { @Override public void run() { if (mCount == 0) { mIsForeground = false; } } }, BACKGROUND_CHECK_DELAY_MS); } @Override public void onActivityCreated(final Activity activity, final Bundle savedInstanceState) { } @Override public void onActivityResumed(final Activity activity) { } @Override public void onActivityPaused(final Activity activity) { } @Override public void onActivitySaveInstanceState(final Activity activity, final Bundle outState) { } @Override public void onActivityDestroyed(final Activity activity) { } } 

My app needs to “reboot” after return from background – show a series of activities, according to client solicitations. After extensive search on how to manage the background/foreground transitions (treated very differently between iOS and Android), I crossed this question. Found very useful help here, specially from the most voted answer and the one flagged as correct. However, simply reinstantiate the root activity EVERY TIME the app enters foreground looked too annoying, when you think about UX. The solution that worked for me, and the one I think’s most adequated – based on the Youtube and Twitter apps functionality – was to combine the answers from @GirishNair and @d60402: Calling the timer when the app’s trimming memory, as follows:

 @Override public void onTrimMemory(int level) { if (stateOfLifeCycle.equals("Stop")) { startActivityTransitionTimer(); } super.onTrimMemory(level); } 

My Timer limit is set to 30 seconds – I’m thinking about increasing this a little.

 private final long MAX_ACTIVITY_TRANSITION_TIME = 30000; 

And when app goes into foreground, is relaunched, or the app’s destroyed, call the method to cancel timer.

On App extension:

 @Override public void onActivityCreated(Activity activity, Bundle arg1) { stopActivityTransitionTimer(); stateOfLifeCycle = "Create"; } @Override public void onActivityDestroyed(Activity activity) { stopActivityTransitionTimer(); stateOfLifeCycle = "Destroy"; } 

On the activity (preferably on a base activity, inherited by the others):

 @Override protected void onStart() { super.onStart(); if (App.wasInBackground) { stopActivityTransitionTimer(); } } 

In my case, when app goes foreground after the max time, a new task is created, so the stopActivityTransitionTimer() is called upon onActivityCreated() or onActivityDestroyed(), in the app extension class – turning unnecessary to call the method in an activity. Надеюсь, поможет.

How about this solution

 public class BaseActivity extends Activity { static String currentAct = ""; @Override protected void onStart() { super.onStart(); if (currentAct.equals("")) Toast.makeText(this, "Start", Toast.LENGTH_LONG).show(); currentAct = getLocalClassName(); } @Override protected void onStop() { super.onStop(); if (currentAct.equals(getLocalClassName())) { currentAct = ""; Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show(); } } } 

All Activity need to extends BaseActivity.

When an activity call another (A->B) then currentAct is not equal getLocalClassName() because the onStart() of the second activity (B) is called before the onStop() of the first (A) ( https://developer.android.com/guide/components/activities.html#CoordinatingActivities ).

When the user press the home button or change between application will just call onStop() and then currentAct is equal getLocalClassName().

This appears to be one of the most complicated questions in Android since (as of this writing) Android doesn’t have iOS equivalents of applicationDidEnterBackground() or applicationWillEnterForeground() callbacks. I used an AppState Library that was put together by @jenzz .

[AppState is] a simple, reactive Android library based on RxJava that monitors app state changes. It notifies subscribers every time the app goes into background and comes back into foreground.

It turned out this is exactly what I needed, especially because my app had multiple activities so simply checking onStart() or onStop() on an activity wasn’t going to cut it.

First I added these dependencies to gradle:

 dependencies { compile 'com.jenzz.appstate:appstate:3.0.1' compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1' } 

Then it was a simple matter of adding these lines to an appropriate place in your code:

 //Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable Observable appState = RxAppStateMonitor.monitor(myApplication); //where myApplication is a subclass of android.app.Application appState.subscribe(new Consumer() { @Override public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception { switch (appState) { case FOREGROUND: Log.i("info","App entered foreground"); break; case BACKGROUND: Log.i("info","App entered background"); break; } } }); 

Depending on how you subscribe to the observable, you may have to unsubscribe from it to avoid memory leaks. Again more info on the github page .

By using below code I’m able to get my app foreground or background state.

For more detail about it’s working, strong text click here

 import android.content.ComponentCallbacks2; import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private Context context; private Toast toast; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; } private void showToast(String message) { //If toast is already showing cancel it if (toast != null) { toast.cancel(); } toast = Toast.makeText(context, message, Toast.LENGTH_SHORT); toast.show(); } @Override protected void onStart() { super.onStart(); showToast("App In Foreground"); } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { showToast("App In Background"); } } } 

Create class with name MyApp like below:

 public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { private Context context; public void setContext(Context context) { this.context = context; } private boolean isInBackground = false; @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { isInBackground = true; Log.d("status = ","we are out"); } } @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { if(isInBackground){ isInBackground = false; Log.d("status = ","we are in"); } } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } } 

Then, everywhere you want (better first activity launched in app), add the code below:

 MyApp myApp = new MyApp(); registerComponentCallbacks(myApp); getApplication().registerActivityLifecycleCallbacks(myApp); 

Готово! Now when the app is in the background, we get log status : we are out and when we go in app, we get log status : we are out

You can achieve this easily with the help of ActivityLifecycleCallbacks and ComponentCallbacks2 something like below.

Create a class AppLifeCycleHandler implementing above said interfaces.

 package com.sample.app; import android.app.Activity; import android.app.Application; import android.content.ComponentCallbacks2; import android.content.res.Configuration; import android.os.Bundle; /** * Created by Naveen on 17/04/18 */ public class AppLifeCycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { AppLifeCycleCallback appLifeCycleCallback; boolean appInForeground; public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) { this.appLifeCycleCallback = appLifeCycleCallback; } @Override public void onActivityResumed(Activity activity) { if (!appInForeground) { appInForeground = true; appLifeCycleCallback.onAppForeground(); } } @Override public void onTrimMemory(int i) { if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { appInForeground = false; appLifeCycleCallback.onAppBackground(); } } @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } interface AppLifeCycleCallback { void onAppBackground(); void onAppForeground(); } } 

In your class which extends Application implement AppLifeCycleCallback to get the callbacks when app switches between foreground and background. Something like below.

 public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{ @Override public void onCreate() { super.onCreate(); AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this); registerActivityLifecycleCallbacks(appLifeCycleHandler); registerComponentCallbacks(appLifeCycleHandler); } @Override public void onAppBackground() { Log.d("LifecycleEvent", "onAppBackground"); } @Override public void onAppForeground() { Log.d("LifecycleEvent", "onAppForeground"); } } 

Надеюсь это поможет.

EDIT As an alternative you can now use Life cycle aware architecture component.

Давайте будем гением компьютера.