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

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

Ответ 1

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

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

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

Ответ 2

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

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

Theres простой образец, представленный в этом ответе, но я написал пример приложения и сообщение в блоге об этом.

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

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

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

Если у вас нет оснований для того, чтобы вы не использовали новые компоненты архитектуры (и есть некоторые, особенно если вы нацелились на сверхбыстрый 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) и выше.

Оказывается, когда ваше приложение не имеет более видимого интерфейса, срабатывает обратный вызов. Обратный вызов, который вы можете реализовать в пользовательском классе, называется 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().

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

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

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);

И это так.

Ответ 3

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

Во-первых, я использовал экземпляр 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 будет false.

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

Ответ 4

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


Фактическое решение в соответствии с Google I/O talk:

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
    }
  }

}

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

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

Ответ 5

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.

Также использование этой функции требует dependencies:

implementation "android.arch.lifecycle:extensions:1.1.1" 
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

Ответ 6

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

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;
        }
    }
}

Затем добавьте это в свой класс onCreate() вашего класса

public class MyApp extends android.app.Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}

Ответ 7

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

Идея есть, когда на переднем плане 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() в более поздних версиях кода. Кроме того, я добавляю супер вызовы, которые отсутствовали в моем первоначальном сообщении, потому что это была скорее концепция, чем рабочий код.

Ответ 8

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

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

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

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> 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, что хорошо. Вместо этого это немного сложнее реализовать.

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

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

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

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

Ответ 9

Создайте класс, который расширяет 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
        }
    }

Ответ 10

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

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

Помните, что если пользователь нажимает кнопку "домой" на экране настроек, onUserLeaveHint будет вызываться в вашей активности настроек, а когда они возвратятся, то в вашем настройке будет вызываться onResume. Если у вас есть только этот код обнаружения в вашем основном действии, вы пропустите этот вариант использования. Чтобы иметь этот код во всех ваших действиях без дублирующего кода, у вас есть абстрактный класс активности, который расширяет 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 {
    ...
}

Ответ 11

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

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

Ответ 12

Пакет android.arch.lifecycle предоставляет классы и интерфейсы, которые позволяют создавать компоненты с учетом жизненного цикла.

Ваше приложение должно реализовывать интерфейс LifecycleObserver:

public class MyApplication extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onAppBackgrounded() {
        Log.d("MyApp", "App in background");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onAppForegrounded() {
        Log.d("MyApp", "App in foreground");
    }
}

Для этого вам нужно добавить эту зависимость в ваш файл build.gradle:

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}

В соответствии с рекомендациями Google вы должны минимизировать код, выполняемый в методах действий жизненного цикла:

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

Вы можете прочитать больше здесь: https://developer.android.com/topic/libraries/architecture/lifecycle

Ответ 13

В своем приложении добавьте обратный вызов и проверьте на активность 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();
            }
        }
    });
}

Ответ 14

Я создал проект на Github app-foreground-background-listen

Создайте BaseActivity для всех действий в вашем приложении.

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
    }
}

Теперь используйте этот BaseActivity как суперкласс всей вашей деятельности, такой как MainActivity, расширяет BaseActivity, а onAppStart вызывается при запуске приложения, а onAppPause() вызывается, когда приложение переходит в фоновый режим с любого экрана.

Ответ 15

Это довольно просто с ProcessLifecycleOwner

Добавьте эти зависимости

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

В Котлине:

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")
    }
}

Тогда в вашей основной деятельности:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

Смотрите мою статью по этой теме: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

Ответ 16

Вы можете использовать ProcessLifecycleOwner, чтобы прикрепить к нему наблюдателя жизненного цикла.

  public class ForegroundLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onAppCreated() {
        Timber.d("onAppCreated() called");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppStarted() {
        Timber.d("onAppStarted() called");
    }

    @OnLifecycleEvent(Event.ON_RESUME)
    public void onAppResumed() {
        Timber.d("onAppResumed() called");
    }

    @OnLifecycleEvent(Event.ON_PAUSE)
    public void onAppPaused() {
        Timber.d("onAppPaused() called");
    }

    @OnLifecycleEvent(Event.ON_STOP)
    public void onAppStopped() {
        Timber.d("onAppStopped() called");
    }
}

затем в onCreate() вашего класса Application вы вызываете это:

ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());

с этим вы сможете захватывать события ON_PAUSE и ON_STOP вашего приложения, которые происходят, когда оно идет в фоновом режиме.

Ответ 17

Изменить 2: То, что я написал ниже, на самом деле не работает. Google отклонил приложение, которое включает вызов ActivityManager.getRunningTasks(). Из документации видно, что этот API предназначен только для целей отладки и разработки. Я буду обновлять этот пост, как только у меня будет время обновить проект GitHub ниже с помощью новой схемы, которая использует таймеры и почти так же хороша.

Изменить 1: я написал сообщение в блоге и создал простой репозиторий GitHub, чтобы сделать это очень легко.

Принятый и наиболее подходящий ответ - это не самый лучший подход. Наивысшая версия ответа isApplicationBroughtToBackground() не обрабатывает ситуацию, когда основное действие приложения приводит к активности, которая определена в одном приложении, но имеет другой пакет Java. Я придумал способ сделать это, что будет работать в этом случае.

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

public static boolean isApplicationBroughtToBackground(final Activity activity) {
  ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);

  // Check the top Activity against the list of Activities contained in the Application 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;
}

Ответ 18

Я нашел хороший метод для обнаружения приложения, будь то передний или задний фон. Вот мой код. Надеюсь, это поможет вам.

/**
 * 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();

}

Ответ 19

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

protected void onRestart()

Разница между новыми запусками и перезапусками.

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

Ответ 20

Нет никаких простых методов жизненного цикла, чтобы сказать вам, когда все Приложение переходит в фоновый режим.

Я сделал это простым способом. Следуйте приведенным ниже инструкциям для определения фона приложения/фазы переднего плана.

С небольшим обходным путем, это возможно. Здесь на помощь приходит ActivityLifecycleCallbacks. Позвольте мне пройти через шаг за шагом.

  1. Сначала создайте класс, который расширяет приложение android.app.Application и реализует интерфейс ActivityLifecycleCallbacks. В Application.onCreate() зарегистрируйте обратный вызов.

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
    
  2. Зарегистрируйте класс "App" в манифесте, как показано ниже, <application android:name=".App".

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

    Объявите 2 переменные, как показано ниже в классе "App".

    private int activityReferences = 0;
    private boolean isActivityChangingConfigurations = false;
    

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

  4. Используя следующий код, вы можете определить, выходит ли приложение на передний план.

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
    
  5. Это как определить, работает ли приложение в фоновом режиме.

    @Override
    public void onActivityStopped(Activity activity) {
        isActivityChangingConfigurations = activity.isChangingConfigurations();
        if (--activityReferences == 0 && !isActivityChangingConfigurations) {
            // App enters background
        }
    }
    

Как это устроено:

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

Предположим, что пользователь запускает приложение и запускает активность A запуска. Жизни жизненного цикла будут,

A.onCreate()

A.onStart() (++activityReferences == 1) (приложение выходит на передний план)

A.onResume()

Теперь активность A начинает деятельность B.

A.onPause()

B.onCreate()

B.onStart() (++activityReferences == 2)

B.onResume()

A.onStop() (--activityReferences == 1)

Затем пользователь переходит обратно из действия B,

B.onPause()

A.onStart() (++activityReferences == 2)

A.onResume()

B.onStop() (--activityReferences == 1)

B.onDestroy()

Затем пользователь нажимает кнопку "Домой",

A.onPause()

A.onStop() (--activityReferences == 0) (приложение входит в фоновый режим)

В случае, если пользователь нажимает кнопку "Домой" в "Деятельности B" вместо кнопки "Назад", он все равно останется прежним, а ActivityReferences будет равен 0. Следовательно, мы можем определить, как приложение входит в фоновый режим.

Итак, isActivityChangingConfigurations роль isActivityChangingConfigurations? В приведенном выше сценарии предположим, что действие B меняет ориентацию. Последовательность обратного вызова будет,

B.onPause()

B.onStop() (--activityReferences == 0) (приложение входит в фон??)

B.onDestroy()

B.onCreate()

B.onStart() (++activityReferences == 1) (приложение выходит на передний план??)

B.onResume()

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

Ответ 21

Правильный ответ здесь

Создайте класс с именем MyApp, как показано ниже:

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() {

    }
}

Затем везде, где вы хотите (лучше сначала запустить приложение в приложении), добавьте код ниже:

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

Готово! Теперь, когда приложение находится в фоновом режиме, мы получаем status: we are out журнала status: we are out и когда мы заходим в приложение, мы получаем status: we are out журнала status: we are out

Ответ 22

Я использовал это с помощью Google Analytics EasyTracker, и это сработало. Он может быть расширен, чтобы делать то, что вы ищете, используя простое целое число.

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) {

            }
        });
    }
}

Ответ 23

Мое решение было вдохновлено ответом @d60402, а также полагается на временное окно, но не использует 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();
  }
}

где SingletonApplication является расширением класса Application:

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

Ответ 24

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

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

 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) {

    }
}

и просто зарегистрируйте его в своем классе приложений, как показано ниже:

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}

Ответ 25

Это, кажется, один из самых сложных вопросов в Android с тех пор (на момент написания этой статьи) Android не имеет эквивалентов iOS для обратных вызовов applicationDidEnterBackground() или applicationWillEnterForeground(). Я использовал AppState Library, которая была собрана @jenzz.

[AppState - простая, реактивная Android-библиотека, основанная на RxJava, которая отслеживает изменения состояния приложения. Он уведомляет подписчиков каждый раз, когда приложение переходит в фоновый режим и возвращается на передний план.

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

Сначала я добавил эти зависимости в gradle:

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

Тогда было просто добавить эти строки в подходящее место в вашем коде:

//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
    @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;
        }
    }
});

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

Ответ 26

Это измененная версия ответа @d60402: fooobar.com/questions/26530/...

Здесь все упоминается. Но вместо того, чтобы иметь Base Activity и сделать это как родительский для каждого действия и переопределить onResume() и onPause, выполните следующие действия:

В вашем классе приложения добавьте строку:

registerActivityLifecycleCallbacks (обратный вызов Application.ActivityLifecycleCallbacks);

Этот callback имеет все методы жизненного цикла активности, и теперь вы можете переопределить onActivityResumed() и onActivityPaused().

Взгляните на этот Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

Ответ 27

Это можно легко сделать с помощью ActivityLifecycleCallbacks и ComponentCallbacks2 как показано ниже.

Создайте класс AppLifeCycleHandler реализующий выше указанные интерфейсы.

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();
  }
}

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

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 В качестве альтернативы теперь вы можете использовать компонент архитектуры, поддерживающий жизненный цикл.

Ответ 28

Поскольку я не нашел никакого подхода, который также обрабатывает ротацию, не проверяя отметки времени, я думал, что я также расскажу, как мы теперь это делаем в нашем приложении. Единственным дополнением к этому ответу fooobar.com/questions/26530/... является то, что мы также учитываем ориентацию.

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {

   // Members

   private var mAppIsInBackground = false
   private var mCurrentOrientation: Int? = null
   private var mOrientationWasChanged = false
   private var mResumed = 0
   private var mPaused = 0

Затем для обратных вызовов у нас есть первое резюме:

   // ActivityLifecycleCallbacks

   override fun onActivityResumed(activity: Activity?) {

      mResumed++

      if (mAppIsInBackground) {

         // !!! App came from background !!! Insert code

         mAppIsInBackground = false
      }
      mOrientationWasChanged = false
    }

И onActivityStopped:

   override fun onActivityStopped(activity: Activity?) {

       if (mResumed == mPaused && !mOrientationWasChanged) {

       // !!! App moved to background !!! Insert code

        mAppIsInBackground = true
    }

И затем, здесь добавляется: Проверка изменений ориентации:

   override fun onConfigurationChanged(newConfig: Configuration) {

       if (newConfig.orientation != mCurrentOrientation) {
           mCurrentOrientation = newConfig.orientation
           mOrientationWasChanged = true
       }
       super.onConfigurationChanged(newConfig)
   }

Это. Надеюсь, это поможет кому-то :)

Ответ 29

Мы можем расширить это решение, используя LiveData:

class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {

    private var lifecycleListener: LifecycleObserver? = null

    override fun onActive() {
        super.onActive()
        lifecycleListener = AppLifecycleListener().also {
            ProcessLifecycleOwner.get().lifecycle.addObserver(it)
        }
    }

    override fun onInactive() {
        super.onInactive()
        lifecycleListener?.let {
            this.lifecycleListener = null
            ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
        }
    }

    internal inner class AppLifecycleListener : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onMoveToForeground() {
            value = State.FOREGROUND
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onMoveToBackground() {
            value = State.BACKGROUND
        }
    }

    enum class State {
        FOREGROUND, BACKGROUND
    }
}

Теперь мы можем подписаться на эту LiveData и ловить нужные события. Например:

appForegroundStateLiveData.observeForever { state ->
    when(state) {
        AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
        AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
    }
}

Ответ 30

Эти ответы не кажутся правильными. Эти методы также называются, когда начинается и заканчивается другое действие. Что вы можете сделать, так это держать глобальный флаг (да, глобальные переменные плохие:) и присваивать этому значение true каждый раз, когда вы начинаете новое действие. Установите значение false в onCreate каждого действия. Затем в onPause вы проверяете этот флаг. Если он ошибочен, ваше приложение переходит в фоновый режим или его убивают.