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

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

46 ответов

Решение

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

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

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ / ЗАМЕТКИ (апрель 2015 г.): Прежде чем перейти к копированию и вставке этого кода, обратите внимание, что я обнаружил пару случаев, когда он может быть ненадежным на 100% и должен сочетаться с другими методами для достижения наилучших результатов. Примечательно, что есть два известных случая, когда onTrimMemory обратный вызов не гарантированно будет выполнен:

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

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

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

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

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

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

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

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

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

Теперь запустите приложение и нажмите "Домой". Ваш 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);

И это все.

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

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

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

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,

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


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

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

Затем добавьте это в ваш 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<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 (), чтобы установить переменную, которая указывает на это, а затем сбросить ее в onPostResume (), который является последним методом, запускаемым при создании / возобновлении действия.

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

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

Пакет 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

ActivityLifecycleCallbacks может быть интересен, но он недостаточно хорошо документирован.

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

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

You can use the ProcessLifecycleOwner attaching a lifecycle observer to it.

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

then on the onCreate() of your Application class you call this:

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

with this you will be able to capture the events of ON_PAUSE and ON_STOP of your application that happen when it goes in background.

Это довольно просто с 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

Я создал проект на Github https://github.com/kiranboghra/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 в качестве суперкласса всей вашей Activity, например MainActivity расширяет BaseActivity, и onAppStart будет вызываться при запуске приложения, а onAppPause() - при переходе приложения в фоновый режим с любого экрана.

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

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

С небольшим обходным путем, это возможно. Здесь на помощь приходит 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" в Манифесте, как показано ниже,

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

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

<pre><code>
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
</code></pre>

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

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

<

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

    
         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? В приведенном выше сценарии предположим, что действие B меняет ориентацию. Последовательность обратного вызова будет,

B.onPause () B.onStop () (--activityReferences == 0) (приложение входит в фон??) B.onDestroy() B.onCreate() B.onStart() (++activityReferences == 1) (приложение выходит на передний план??) B.onResume()

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

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

защищенный void onRestart ()

Различаться между новыми запусками и перезапусками.

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

Редактировать 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'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;
}

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

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

}

Вы можете просто вызвать этот метод в своем классе приложения

ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                Log.e(TAG, "onStateChanged: " + event.toString());
            }
        });

Lifecycle.Event просто вернет состояние приложения

ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY

он вернет ON_PAUSE и ON_STOP, когда приложение перейдет в фоновый режим, и вернет ON_START и ON_RESUME, когда приложение перейдет на передний план

Поскольку я не нашел никакого подхода, который также обрабатывает вращение без проверки меток времени, я подумал, что я также поделюсь тем, как мы сейчас делаем это в нашем приложении. Единственное дополнение к этому ответу /questions/9918120/kak-opredelit-kogda-prilozhenie-android-perehodit-v-fonovyij-rezhim-i-vozvraschaetsya-na-perednij-plan/9918144#9918144 заключается в том, что мы также принимаем во внимание ориентацию.

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
    }

И на ActiveStopped:

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

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

LifecycleObserverне рекомендуется. ИспользоватьDefaultLifecycleObserverвместо:

      public class YourApplication extends Application implements DefaultLifecycleObserver {

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

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStart(owner);
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onResume(owner);
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onPause(owner);
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onStop(owner);
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        DefaultLifecycleObserver.super.onDestroy(owner);
    }
}

Зависимости:

        implementation 'androidx.lifecycle:lifecycle-common:2.5.1'
  implementation 'androidx.lifecycle:lifecycle-process:2.5.1'

Я использовал это с 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) {

            }
        });
    }
}

Создайте класс с именем 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

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

      import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import java.util.Timer
import java.util.TimerTask

/**
 * An observer class to listen on the app's lifecycle.
 */
class AppLifecycleObserver(
    private val onAppGoesToBackground: () -> Unit = {},
    private val onAppEntersForeground: () -> Unit = {}
) : LifecycleEventObserver {

    private val debounce = DebouncingTimer(timeout = 10)

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        debounce.refresh {
            when (event.targetState) {
                Lifecycle.State.CREATED -> onAppGoesToBackground()
                Lifecycle.State.RESUMED -> onAppEntersForeground()
                else -> Unit
            }
        }
    }

    fun attach() {
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    fun detach() {
        ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
    }

    private class DebouncingTimer(private val timeout: Long) {

        private var timer: Timer? = null

        fun refresh(job: () -> Unit) {
            timer?.cancel()
            timer = Timer()
            timer?.schedule(object : TimerTask() {
                override fun run() = job.invoke()
            }, timeout)
        }
    }
}

Просто нужно создать экземпляр AppLifecycleObserver:

      private val appLifecycleObserver = AppLifecycleObserver(
        onAppGoesToBackground = { // do whatever... },
        onAppEntersForeground = { // do whatever... }
    )
      // Attach the observer when it is needed:
appLifecycleObserver.attach()

// Remove when there is no need to it:
appLifecycleObserver.detach()

Не забудьте добавить правильную версию зависимости:

      implementation("androidx.lifecycle:lifecycle-process:$lifecycle_version")

Вы можете легко достичь этого с помощью 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");
    }
}

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

РЕДАКТИРОВАТЬ В качестве альтернативы теперь вы можете использовать компонент архитектуры с учетом жизненного цикла.

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

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

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

Этого можно добиться тремя способами:

  • Архитектура единого действия
  • ActivityLifecycleCallback
  • LifecycleObserver и ProcessLifecycleOwner

Подробно об этом написали здесь. Надеюсь, это поможет.

Что я сделал, так это удостоверился, что все действия в приложении запускаются с startActivityForResult затем проверка, был ли вызван onActivityResult перед onResume. Если это не так, это означает, что мы только что вернулись откуда-то за пределами нашего приложения.

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;
}
Другие вопросы по тегам