Я запутался здесь .. почему Android не может обеспечить простое переопределение класса приложения для этого? Это слишком сложно знать на уровне платформы? @ Переопределить защищенный void onApplicationSentToBackground () {}
Чак Д,
2
@ChuckD - это имело бы смысл, и это то, что Android SDK, похоже, не хочет делать время от времени. : /
У iOS есть это в пиках, не уверен, почему Google делает это так сложно. Это такая очевидная необходимость.
Джерри Дестремпс
Ответы:
388
Есть несколько способов определить, работает ли ваше приложение в фоновом режиме, но только один из них является полностью надежным:
Правильное решение (кредиты идут к Дэну , CommonsWare и NeTeInStEiN )
видимости Трек вашего приложения самостоятельно , используя Activity.onPause, Activity.onResumeметоды. Сохраните статус «видимости» в каком-то другом классе. Хороший выбор - ваша собственная реализация Applicationили или Service(есть также несколько вариантов этого решения, если вы хотите проверить видимость активности из службы).
Пример
реализации пользовательского Applicationкласса (обратите внимание на isActivityVisible()статический метод):
Добавьте onPauseи onResumeк каждому Activityв проекте (вы можете создать общего предка для своих действий, если хотите, но если ваше действие уже расширено из MapActivity/ ListActivityи т. Д., Вам все еще нужно написать следующее вручную):
Обновление ActivityLifecycleCallbacks было добавлено на уровне API 14 (Android 4.0). Вы можете использовать их, чтобы отслеживать, видна ли активность вашего приложения в данный момент для пользователя. Проверьте ответ Cornstalks ниже для деталей.
Неправильное, которое
я использовал, чтобы предложить следующее решение:
Вы можете обнаружить в настоящее время передний план / фоновое приложение с ActivityManager.getRunningAppProcesses() которое возвращает список RunningAppProcessInfoзаписей. Чтобы определить, находится ли ваше приложение на переднем плане, проверьте RunningAppProcessInfo.importanceполе на равенство RunningAppProcessInfo.IMPORTANCE_FOREGROUNDwhile и RunningAppProcessInfo.processNameимя пакета вашего приложения.
Кроме того, если вы позвоните ActivityManager.getRunningAppProcesses()из потока пользовательского интерфейса приложения, он вернет значение IMPORTANCE_FOREGROUNDдля вашей задачи независимо от того, находится ли он на переднем плане или нет. Вызовите его в фоновом потоке (например, через AsyncTask), и он вернет правильные результаты.
Хотя это решение может работать (и оно действительно работает большую часть времени), я настоятельно рекомендую воздержаться от его использования. И вот почему. Как написала Дайан Хэкборн :
Эти API-интерфейсы предназначены не для того, чтобы приложения основывали свой поток пользовательского интерфейса, а для того, чтобы показывать пользователю запущенные приложения, диспетчер задач или тому подобное.
Да, в памяти хранится список этих вещей. Тем не менее, он отключен в другом процессе, управляемом потоками, работающими отдельно от вас, и вы не можете рассчитывать на то, что (a) увидите вовремя для принятия правильного решения или (b) получите непротиворечивую картину к тому времени, когда вы вернетесь. Кроме того, решение о том, к какому «следующему» действию перейти, всегда принимается в момент, когда должно произойти переключение, и только в той точной точке (где состояние действия кратко блокируется для выполнения переключения), что мы на самом деле точно знаю, что будет дальше.
И реализация и глобальное поведение здесь не гарантируется, что останутся такими же в будущем.
Хотелось бы, чтобы я прочитал это до того, как опубликовал ответ на SO, но, надеюсь, еще не поздно признать мою ошибку.
Другое неправильное решение, которое библиотека Droid-Fu упоминает в одном из ответов, использует ActivityManager.getRunningTasksдля своего isApplicationBroughtToBackgroundметода. Посмотрите комментарий Дайанны выше и тоже не используйте этот метод.
Чтобы узнать, нажали ли вы кнопку «Домой» или какое-либо другое приложение, вы получили фокус: 1) внедрите хорошее решение . 2) По OnStopзапросу isActivityVisible.
Брейс Габин
28
К сожалению, ваше «правильное» решение не работает для меня. Представьте, что вы переключаетесь между действиями в вашем приложении. Затем происходит то, что ваш флаг 'inForeground' выглядит следующим образом: True, False (между 1-й активностью onPause и 2-й активностью onResume), затем снова True и т. Д. Затем вам потребуется какой-то гистерезис.
Раду
14
Это решение не работает, если вы не можете напрямую контролировать все действия. Например, если у вас есть Activity от стороннего sdk или даже запущено намерение ACTION_VIEW.
user123321
66
Андроид такой долбаный крушение. Никто не думал, что кто-то может захотеть сохранить данные уровня приложения? Дай мне перерыв
8
Похоже, реальный ответ на этот вопрос «Вы не можете проверить это правильно». Так называемое «правильное» решение - в лучшем случае обходной путь, поэтому используется ActivityLifecycleCallbacks. Вам все еще нужно рассмотреть возможность переключения между действиями, которые будут зарегистрированы как "не на переднем плане". Меня поражает, что вы не можете проверить такие простые вещи ...
Я оставлю свой оригинальный ответ здесь ради потомков. Это было лучшее из доступных в 2012 году, но теперь Android имеет соответствующую поддержку для этого.
Оригинальный ответ
Ключ использует ActivityLifecycleCallbacks (обратите внимание, что для этого требуется Android API уровня 14 (Android 4.0)). Просто проверьте, равно ли количество остановленных действий количеству запущенных действий. Если они равны, ваша заявка в фоновом режиме. Если есть еще запущенные действия, ваше приложение все еще отображается. Если действия возобновлены, а не приостановлены, приложение не только отображается, но и на переднем плане. Существуют 3 основных состояния, в которых ваша деятельность может находиться, затем: видимая и на переднем плане, видимая, но не на переднем плане, и не видимая и не на переднем плане (то есть на заднем плане).
Отличная вещь в этом методе состоит в том, что он не имеет асинхронных проблем getRunningTasks(), но вам также не нужно изменять все Activityв вашем приложении для установки / сброса чего-либо в onResumed()/ onPaused(). Это всего лишь несколько строк кода, которые самодостаточны и работают во всем приложении. Плюс, здесь нет никаких фанки-разрешений.
MyLifecycleHandler.java:
publicclassMyLifecycleHandlerimplementsActivityLifecycleCallbacks{// I use four separate variables here. You can, of course, just use two and// increment/decrement them instead of using four and incrementing them all.privateint resumed;privateint paused;privateint started;privateint stopped;@Overridepublicvoid onActivityCreated(Activity activity,Bundle savedInstanceState){}@Overridepublicvoid onActivityDestroyed(Activity activity){}@Overridepublicvoid onActivityResumed(Activity activity){++resumed;}@Overridepublicvoid onActivityPaused(Activity activity){++paused;
android.util.Log.w("test","application is in foreground: "+(resumed > paused));}@Overridepublicvoid onActivitySaveInstanceState(Activity activity,Bundle outState){}@Overridepublicvoid onActivityStarted(Activity activity){++started;}@Overridepublicvoid onActivityStopped(Activity activity){++stopped;
android.util.Log.w("test","application is visible: "+(started > stopped));}// If you want a static function you can use to check if your application is// foreground/background, you can use the following:/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/}
MyApplication.java:
// Don't forget to add it to your manifest by doing// <application android:name="your.package.MyApplication" ...publicclassMyApplicationextendsApplication{@Overridepublicvoid onCreate(){// Simply add the handler, and that's it! No need to add any code// to every activity. Everything is contained in MyLifecycleHandler// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(newMyLifecycleHandler());}}
@Mewzer задал несколько хороших вопросов об этом методе, на которые я хотел бы ответить в этом ответе для всех:
onStop()не вызывается в ситуациях с нехваткой памяти; это проблема здесь?
Нет, документы onStop()говорят:
Обратите внимание, что этот метод никогда не может быть вызван в ситуациях с нехваткой памяти, когда системе не хватает памяти для поддержания процесса вашей активности после вызова метода onPause ().
Ключевым моментом здесь является «поддерживать процесс вашей активности …». Если эта ситуация с нехваткой памяти когда-либо будет достигнута, ваш процесс фактически будет уничтожен (а не только ваша активность). Это означает, что этот метод проверки на фоновую целостность все еще действителен, потому что а) вы все равно не можете проверить фоновую обработку, если ваш процесс убит, и б) если ваш процесс запускается снова (потому что создается новое действие), член переменные (статические или нет) для MyLifecycleHandlerбудут сброшены в 0.
Это работает для изменений конфигурации?
По умолчанию нет. Вы должны явно указать configChanges=orientation|screensize( |со всем, что хотите) в файле манифеста и обработать изменения конфигурации, иначе ваша деятельность будет уничтожена и воссоздана. Если вы не установили это, методы вашей деятельности будет называться в следующем порядке: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. Как видите, перекрытия нет (как правило, при переключении между двумя действиями очень кратко перекрываются два действия, как работает этот метод обнаружения фона). Для того, чтобы обойти это, вы должны установить, configChangesчтобы ваша деятельность не была разрушена. К счастью, мне пришлось установитьconfigChangesуже во всех моих проектах, потому что было нежелательно, чтобы вся моя деятельность разрушалась при повороте / изменении размера экрана, поэтому я никогда не считал это проблематичным. (спасибо dpimka за то, что освежил мою память об этом и исправил меня!)
Одна запись:
Когда я сказал «фон» в этом ответе, я имел в виду «ваше приложение больше не видно». Действия Android могут быть видны, но не на переднем плане (например, если есть прозрачное наложение уведомлений). Вот почему я обновил этот ответ, чтобы отразить это.
Важно знать, что у Android есть странный подвешенный момент при переключении действий, когда ничто не находится на переднем плане . По этой причине, если вы проверяете, находится ли ваше приложение на переднем плане при переключении между действиями (в том же приложении), вам будет сказано, что вы не на переднем плане (даже если ваше приложение все еще является активным приложением и отображается ).
Вы можете проверить , если ваше приложение находится на переднем плане в вашей Activity«S onPause()метод послеsuper.onPause() . Просто вспомните странное состояние неопределенности, о котором я только что говорил.
Вы можете проверить , если ваше приложение видимое (то есть , если это не в фоновом режиме) в вашем Activity«S onStop()методе послеsuper.onStop() .
Это выглядит интересно - но что происходит в ситуациях с нехваткой памяти? Не гарантируется, что onStop () будет вызван. Можем ли мы когда-нибудь попасть в ситуацию, когда onStop () не вызывается и счетчик остановок не увеличивается - это означает, что фоновая проверка больше не является надежной? Или это никогда не произойдет?
Mewzer
1
Кроме того, это будет игнорировать изменения конфигурации? Или приложение будет считаться фоновым, если действие воссоздается в результате изменения конфигурации (например, изменение ориентации)? Извините, за вопросы, но я думаю, что вы на что-то и заинтересованы, чтобы знать, работает ли это в этих крайних случаях.
Mewzer
1
@Mewzer: Я собирался ответить в виде комментария, но для того, чтобы получить эти ответы, потребуется немного набрать текст, поэтому вернитесь через несколько минут, и я отредактирую свой ответ.
Cornstalks
1
@ Мьюзер: Вы должны найти свои ответы сейчас. Дайте мне знать, если есть еще вопросы!
Cornstalks
2
@Mewzer: Я только что добавил заметку, которая может вас заинтересовать. В частности, проверьте наличие фона onStop()после super.onStop(). Не проверяйте фоновый режим в onPause().
classArchLifecycleApp:Application(),LifecycleObserver{override fun onCreate(){super.onCreate()ProcessLifecycleOwner.get().lifecycle.addObserver(this)}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded(){// App in foreground}}
Ява:
publicclassArchLifecycleAppextendsApplicationimplementsLifecycleObserver{@Overridepublicvoid onCreate(){super.onCreate();ProcessLifecycleOwner.get().getLifecycle().addObserver(this);}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)publicvoid onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)publicvoid onAppForegrounded(){// App in foreground}}
в приложении
dependencies {...
implementation "android.arch.lifecycle:extensions:1.1.0"//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"}
allprojects {
repositories {...
google()
jcenter()
maven { url 'https://maven.google.com'}}}
Это определенно должен быть правильный ответ! Это работало как очарование: D
JaviOverflow
2
Это работает отлично, я также немного изменил, чтобы мне было легче получить доступ к переднему плану / состоянию фона вне этого класса: companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }тогда вы можете получить состояние переднего плана сArchLifecycleApp.isForeground()
Jose Jet
2
О, чувак, это намного лучше, чем мой старый ответ. +1 от меня. Я обновил свой ответ, чтобы указать людям на ваш.
Кукурузные початки
2
Хотя это правильный ответ, нет необходимости реализовывать обратные вызовы, вы можете просто запросить ProcessLifecycleOwner, когда захотите. Проверьте stackoverflow.com/a/52678290/6600000
Кейван Эсбати
2
Как говорит док The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , это не работает для multiple processesприложений, есть ли какой-нибудь API, который мы можем достичь элегантно?
Acntwww
23
Начиная с версии 26 библиотеки поддержки, вы можете использовать ProcessLifecycleOwner , просто добавьте его в свою зависимость, как описано здесь , например:
dependencies {def lifecycle_version ="1.1.1"// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"// alternatively - Lifecycles only (no ViewModel or LiveData).// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"// use kapt for Kotlin}
А затем просто запрашивайте в ProcessLifecycleOwnerлюбое время состояние приложения, примеры:
//Check if app is in backgroundProcessLifecycleOwner.get().getLifecycle().getCurrentState()==Lifecycle.State.CREATED;//Check if app is in foregroundProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Спасибо, это лучший и самый простой способ, который подходит для любой части вашего кода, особенно при использовании fcm.
Михаэ Хил
если приложение будет полностью закрыто, что вернет первый метод?
Евгений Мишустин
@EvgeniyMishustin, который зависит от текущего состояния приложения, но обычно вы видите CREATED, а затем DESTROYED, и после этого вы не будете получать никаких новых событий.
Кейван Эсбати
Так где же какое-либо утверждение "IF", чтобы увидеть, если приложение находится в фоновом режиме (на переднем плане) ???
ekashking
@ekashking просто поместил весь оператор в условие if. Например: if (ProcessLifecycleOwner.get (). GetLifecycle (). GetCurrentState (). IsAtLeast (Lifecycle.State.STARTED)) => Приложение находится на переднем плане
Кейван Эсбати,
20
Начиная с Android API 16 существует простой способ проверить, находится ли приложение на переднем плане. Это может быть небезопасно, но никакие методы на Android не являются надежными. Этот метод достаточно хорош для использования, когда ваша служба получает обновление от сервера и должна решить, показывать уведомление или нет (потому что, если пользовательский интерфейс находится на переднем плане, пользователь заметит обновление без уведомления).
должен ли этот код находиться внутри класса Service или другого класса, например, класса Application? Большое спасибо.
Woppi
... везде, где вы хотите использовать его в качестве последней строки, это просто логическое значение, против которого вы будете проверять.
AO_
Это та же методика, что и в AWS Android SDK для push-уведомлений.
spakmad
Имейте в виду, что «определение фона для целей ограничения услуг отличается от определения, используемого управлением памятью; приложение может находиться в фоновом режиме в том, что касается управления памятью, но на переднем плане - в отношении его способности запускать службы».) " developer.android.com/about/versions/oreo/background.html (
ARLabs
Спасибо, это сработало! Я смог использовать этот код в, JobServiceчтобы обнаружить, что служба работает в фоновом режиме.
Idolon's answer is error prone- к сожалению, я должен согласиться с вами. На основании комментария Дайан Хэкборн в группах Google я обновил свой ответ. Проверьте это, пожалуйста, для деталей.
Идолон
2
Это тоже не надежное решение. Один из сценариев не является ли пользователь разобрали панель уведомлений, а затем ни onPause, onStop, ни onResumeсобытие называется. Так что же делать, если ни одно из этих событий не запущено ?!
К сожалению, этот код работает неправильно, когда действие запускается, когда экран выключен. В этом случае onResume и onPause вызываются, создавая isVisible = false.
CoolMind
@CoolMind Не могли бы вы объяснить, каков вариант использования, когда вы запускаете действие в фоновом режиме?
neteinstein
11
Я попытался рекомендовать решение, которое использует Application.ActivityLifecycleCallbacks и многие другие, но они не сработали, как ожидалось. Благодаря Sarge я нашел довольно простое и понятное решение, которое я описываю ниже.
Ключом решения является тот факт, что если у нас есть ActivityA и ActivityB, и мы вызываем ActivityB из ActivityA (а не вызываем ActivityA.finish), то ActivityB onStart()будет вызываться перед ActivityA onStop().
Это также основная разница между onStop()и onPause()что никто не сделал упоминания в статьях , которые я прочитал.
Таким образом, основываясь на поведении этого жизненного цикла, вы можете просто посчитать, сколько раз это делали onStart()и onPause()вызывали в вашей программе. Обратите внимание, что для каждойActivity вашей программы вы должны переопределить onStart()и onStop(), чтобы увеличить / уменьшить статическую переменную, используемую для подсчета. Ниже приведен код, реализующий эту логику. Обратите внимание, что я использую класс, который расширяется Application, поэтому не забудьте объявить Manifest.xmlвнутри тега Application: android:name=".Utilities"хотя он также может быть реализован с использованием простого пользовательского класса.
publicclassUtilitiesextendsApplication{privatestaticint stateCounter;publicvoid onCreate(){super.onCreate();
stateCounter =0;}/**
* @return true if application is on background
* */publicstaticboolean isApplicationOnBackground(){return stateCounter ==0;}//to be called on each Activity onStart()publicstaticvoid activityStarted(){
stateCounter++;}//to be called on each Activity onStop()publicstaticvoid activityStopped(){
stateCounter--;}}
Теперь в каждом действии нашей программы мы должны переопределять onStart()и onStop()и увеличивать / уменьшать, как показано ниже:
@Overridepublicvoid onStart(){super.onStart();Utilities.activityStarted();}@Overridepublicvoid onStop(){Utilities.activityStopped();if(Utilities.isApplicationOnBackground()){//you should want to check here if your application is on background}super.onStop();}
С этой логикой, есть 2 возможных случая:
stateCounter = 0 : Количество остановленных равно количеству запущенных операций, что означает, что приложение работает в фоновом режиме.
stateCounter > 0 : Количество запущенных больше, чем количество остановленных, что означает, что приложение работает на переднем плане.
Обратите внимание: stateCounter < 0будет означать, что больше остановленных действий, чем начатых, что невозможно. Если вы столкнулись с этим случаем, это означает, что вы не увеличиваете / уменьшаете счетчик, как следует.
Вы готовы к работе. Вы должны проверить, находится ли ваше приложение на заднем плане внутри onStop().
Я бы переехал if(Utilities.isApplicationOnBackground()) …в Utilities. Потому что в противном случае только конкретное действие будет реагировать на событие.
Отображаемое имя
10
Нет способа, если вы не отслеживаете это самостоятельно, чтобы определить, являются ли какие-либо из ваших действий видимыми или нет. Возможно, вам следует подумать о том, чтобы задать новый вопрос StackOverflow, объяснив, чего вы пытаетесь добиться от взаимодействия с пользователем, чтобы мы могли предложить вам альтернативные идеи реализации.
В андроиде у нас есть настройка под названием «Фоновые данные». Этот параметр отключает любое фоновое соединение данных, когда приложение работает в фоновом режиме. Я хочу реализовать переключатель «Фоновые данные» для своего приложения, поэтому, когда ни одно из моих действий не будет видно пользователю, я бы хотел, чтобы моя служба прекратила передачу данных, но в тот момент, когда возобновится одно из моих действий, я бы хотел, чтобы возобновить передачу данных
cppdev
1
@cppdev: Будем надеяться, что «передача данных» проводится по Service. Если это так, попросите службу уведомить службу по мере их появления и исчезновения. Если Serviceвыясняется, что никаких видимых действий нет, и он остается таким в течение некоторого времени, остановите передачу данных в следующей точке логического останова. Да, для этого потребуется код для каждого из ваших действий, но сейчас это неизбежно, AFAIK.
CommonsWare
1
Если вы хотите избежать копирования и вставки общего кода между всеми вашими действиями, вы можете создать класс, MyActivityClassнаследующий Activityи реализующий методы жизненного цикла, и сделать все ваши действия наследуемыми MyActivityClass. Это не будет работать для PreferenceActivityили MapActivityхотя (см. Этот вопрос )
Гийом Brunerie
@ CommonsWare Я пытался с OnPause () OnResume (), чтобы он был активен или нет, но если мое приложение не отображается на экране просмотра, если оно работает в фоновом режиме, как проверить, активно оно или нет
Manoj
@ CommonsWare Я пытался с OnPause () OnResume (), что оно активно или нет, но если мое приложение не отображается на экране просмотра, если оно работает в фоновом режиме, как проверить, активно ли оно или нет
Manoj
5
Вы можете использовать ComponentCallbacks2, чтобы определить, находится ли приложение в фоновом режиме. Кстати, этот обратный вызов доступен только в API Level 14 (Ice Cream Sandwich) и выше.
Вы получите вызов метода:
public abstract void onTrimMemory (int level)
если уровень - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDENприложение в фоновом режиме.
Вы можете реализовать этот интерфейс activity, serviceи т. Д.
publicclassMainActivityextendsAppCompatActivityimplementsComponentCallbacks2{@Overridepublicvoid onConfigurationChanged(finalConfiguration newConfig){}@Overridepublicvoid onLowMemory(){}@Overridepublicvoid onTrimMemory(finalint level){if(level ==ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){// app is in background}}}
Опробовал ваш ответ, но не так надежно. обратный вызов onTrimMemory не сработает, когда экран заблокирован, а также при нажатии кнопки «Питание» для блокировки экрана. Также не всегда будет возвращаться TRIM_MEMORY_UI_HIDDEN, если ваше приложение видно и вы открываете другое приложение через уведомление в строке состояния. Единственное надежное решение - реализовать ActivityLifecycleCallbacks и настроить его в соответствии с вариантом использования.
velval
4
Опираясь на @Cornstalks ответ, чтобы включить несколько полезных функций.
Дополнительные функции:
представил одноэлементный шаблон, так что вы можете сделать это где угодно в приложении: AppLifecycleHandler.isApplicationVisible () и AppLifecycleHandler.isApplicationInForeground ()
добавлена обработка повторяющихся событий (см. комментарии // предпринимаем некоторые действия для изменения видимости и // предпринимаем некоторые действия для изменения на переднем плане)
Лучшее решение, которое я придумал, использует таймеры.
Вы запускаете таймер в onPause () и отменяете тот же таймер в onResume (), есть 1 экземпляр Timer (обычно определяется в классе Application). Сам таймер настроен на запуск Runnable через 2 секунды (или любой интервал, который вы считаете подходящим), когда срабатывает таймер, вы устанавливаете флаг, отмечающий приложение как фоновое.
В методе onResume () перед отменой таймера можно запросить флаг фона для выполнения любых операций запуска (например, начать загрузку или включить службы определения местоположения).
Это решение позволяет выполнять несколько операций в заднем стеке и не требует каких-либо разрешений для реализации.
Это решение хорошо работает, если вы также используете шину событий, поскольку ваш таймер может просто инициировать событие, и различные части вашего приложения могут реагировать соответствующим образом.
Я начинаю думать, что это лучшее (хотя и неудачное) решение
dhaag23
Да, это лучшее решение, которое мне удалось. Мне нужно было остановить сканирование по Bluetooth, когда приложение не было предопределено, но я не мог просто использовать onpause, остановку или уничтожение, потому что я не хотел постоянно останавливаться и запускаться, когда пользователь перемещался по приложению.
CaptRespect
3
Если вы включите настройки разработчика «Не сохранять активности» - проверьте, что количество созданных активностей недостаточно. Вы должны проверить также isSaveInstanceState . Мой пользовательский метод isApplicationRunning () проверяет, запущено ли приложение для Android:
Я не понимаю, как это решение может дать мне ответ на простой вопрос в заявлении IF о моей активности (или фрагменте), находится ли мое приложение на заднем плане или на переднем плане. Где заявление "ЕСЛИ" ???
ekashking
2
Чтобы прокомментировать сказанное в CommonsWare и Key, вы можете расширить класс Application и сделать так, чтобы все ваши действия вызывали его в своих методах onPause / onResume. Это позволит вам узнать, какие виды деятельности видны, но, вероятно, это можно сделать лучше.
Можете ли вы уточнить, что именно вы имеете в виду? Когда вы говорите, что работаете в фоновом режиме, вы подразумеваете, что ваше приложение все еще находится в памяти, хотя его нет на экране? Рассматривали ли вы использование Сервисов как более устойчивый способ управления вашим приложением, когда оно не в фокусе?
В андроиде у нас есть настройка под названием «Фоновые данные». Этот параметр отключает любое фоновое соединение данных, когда приложение работает в фоновом режиме. Я хочу реализовать переключатель «Фоновые данные» для своего приложения, поэтому, когда ни одно из моих действий не будет видно пользователю, я бы хотел, чтобы мой сервис прекратил выполнять какую-либо передачу данных, но в момент возобновления одного из моих действий я хотел бы возобновить передачу данных
cppdev
1
Applicationне имеет onPause()или onResume().
CommonsWare
1
@CommonsWare Вы правы, я имел в виду каждую отдельную активность, связываясь с приложением по их паузе / резюме. По сути, это идея, которую вы только что поделились в комментарии к своему ответу, хотя вы использовали Сервисы, и я думаю, это более разумный шаг.
Дэн
2
Я сделал свою собственную реализацию ActivityLifecycleCallbacks. Я использую SherlockActivity, но для обычного класса Activity может работать.
Во-первых, я создаю интерфейс, который имеет все методы для отслеживания жизненного цикла действий:
Активность приостанавливается, когда над ним появляется диалог, поэтому все рекомендуемые решения являются полурешениями. Вам также необходимо создать хуки для диалогов.
Система различает фоновые и фоновые приложения. (Определение фона для целей ограничения услуг отличается от определения, используемого управлением памятью; приложение может находиться в фоновом режиме в том, что касается управления памятью , но на переднем плане - в отношении его способности запускать службы.) считается находящимся на переднем плане, если выполняется любое из следующих условий:
У него есть видимое действие, независимо от того, запущено или приостановлено действие.
У него есть сервис переднего плана.
Другое приложение переднего плана подключается к приложению либо путем привязки к одной из его служб, либо с использованием одного из его поставщиков контента. Например, приложение находится на переднем плане, если к нему привязано другое приложение:
IME
Сервис обоев
Слушатель уведомлений
Голосовой или текстовый сервис
Если ни одно из этих условий не выполняется, приложение считается в фоновом режиме.
Вы должны использовать общие предпочтения для хранения собственности и действовать в соответствии с ней, используя привязку сервисов из ваших действий. Если вы используете только привязку (то есть никогда не используете startService), то ваша служба будет работать только при привязке к ней (привязка onResume и unbind onPause), что заставит ее работать только на переднем плане, и если вы захотите работать с ней. В фоновом режиме вы можете использовать обычную службу начала остановки.
Я думаю, что этот вопрос должен быть более ясным. Когда? Куда? Какова ваша конкретная ситуация, которую вы хотите знать, если ваше приложение в фоновом режиме?
Я просто представляю свое решение по-своему.
Для этого я использую поле «важность» RunningAppProcessInfoкласса в onStopметоде каждого действия в моем приложении, чего можно добиться, просто предоставив BaseActivityрасширение для других действий, которое реализует onStopметод для проверки значения «важность». Вот код:
У меня есть около 10 мероприятий в моей заявке. Поэтому я хочу знать, если ни один из них, если видим для пользователя. В общем, я хочу знать, работает ли мое приложение в целом в фоновом режиме
cppdev
Итак, вы отслеживаете все 10-ти. Или, как предложил CommonsWare, объясните, что вы пытаетесь сделать.
Ключ
3
Это не правильно. Ваша активность видна до onStop; между onPauseи onStopэто видно , но не на переднем плане .
Никгрим
@nickgrim: что не правильно? Я заявил, что после вызова вызывается активность onStop(), которая соответствует тому, что вы написали.
Ключ
@Key: Вы первоначально сказали, пока onPauseне называется: недавнее редактирование исправило вас.
Никгрим
0
Как насчет использования getApplicationState (). IsInForeground ()?
По моему мнению, многие ответы вводят большую нагрузку кода и приносят много сложности и нечитаемости.
Когда люди спрашивают на SO, как общаться между a Serviceи a Activity, я обычно советую использовать LocalBroadcastManager .
Зачем?
Ну, цитируя документы:
Вы знаете, что передаваемые вами данные не покинут ваше приложение, поэтому вам не нужно беспокоиться о утечке личных данных.
Другие приложения не могут отправлять эти трансляции в ваше приложение, поэтому вам не нужно беспокоиться о наличии дыр в безопасности, которые они могут использовать.
Это более эффективно, чем отправка глобальной трансляции через систему.
Не в документах:
Не требует внешних библиотек
Код минимален
Это быстро реализовать и понять
Никаких настраиваемых самореализованных обратных вызовов / ультра-синглтона / внутрипроцессного паттерна вообще ...
Отсутствие сильных ссылок на Activity, Application...
Описание
Итак, вы хотите проверить, находится ли какая-либо из Activityних на переднем плане. Вы обычно делаете это в классе Serviceили в своем Applicationклассе.
Это означает, что ваши Activityобъекты становятся отправителями сигнала (я включен / выключен). Ваш Service, с другой стороны, становится Receiver.
Есть два момента, в которых вашActivity говорит вам, идет ли он на переднем плане или на заднем плане (да только два ... не 6).
Когда Activityвыходит на передний план, onResume()метод срабатывает (также вызывается после onCreate()).
Когда Activityидет в спину, onPause()называется.
Это моменты, в которые вы Activityдолжны послать свой сигнал, Serviceчтобы описать его состояние.
В случае нескольких Activity, помнитеActivity вначале уходит на задний план, затем на передний план выходит другой.
Service/ ApplicationБудет просто продолжать слушать музыку этих сигналов и действовать соответствующим образом .
Код (TLDR)
Вы Serviceдолжны реализовать для BroadcastReceiverтого, чтобы слушать сигналы.
this.localBroadcastReceiver =newBroadcastReceiver(){@Overridepublicvoid onReceive(Context context,Intent intent){// received data if Activity is on / off}}publicstaticfinalIntentFilter SIGNAL_FILTER =newIntentFilter("com.you.yourapp.MY_SIGNAL")
@Overrideprotectedvoid onDestroy(){// I'm dead, no need to listen to anything anymore.LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);}
Теперь вы Activityдолжны сообщить свое состояние.
В Activity::onResume()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put ON boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
В Activity::onPause()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put OFF boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Очень, очень распространенная ситуация
Разработчик: я хочу отправить данные из моего Serviceи обновить Activity. Как я могу проверить, Activityнаходится ли на переднем плане?
Обычно нет необходимости проверять, Activityнаходится ли на переднем плане или нет. Просто отправьте данные через LocalBroadcastManagerваш Service. Если Activityон включен, он будет реагировать и действовать.
В этой очень распространенной ситуации Serviceстановится отправителем, а Activityреализует BroadcastReceiver.
Итак, создайте Receiverв своем Activity. Зарегистрируйте это onResume()и отмените регистрацию в onPause(). Нет необходимости использовать другие методы жизненного цикла .
Определите Receiverповедение в onReceive()(обновите ListView, сделайте это, сделайте это, ...).
Таким образом, он Activityбудет слушать только если он находится на переднем плане и ничего не произойдет, если он находится сзади или уничтожен.
В случае нескольких Activity, Activityответ будет зависеть (если они также реализуютReceiver ).
Если все на заднем плане, никто не ответит, и сигнал просто потеряется.
Отправьте данные Serviceчерез канал Intent(см. Код выше), указав идентификатор сигнала.
За исключением поддержки нескольких окон . Это может быть сложно (пожалуйста, проверьте это при необходимости) ...
fun isAppInForeground():Boolean{
val activityManager = getSystemService(Context.ACTIVITY_SERVICE)asActivityManager?:returnfalse
val appProcesses = activityManager.runningAppProcesses ?:returnfalse
val packageName = packageName
for(appProcess in appProcesses){if(appProcess.importance ==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName){returntrue}}returnfalse}
Ни один из ответов не вполне соответствовал конкретному случаю, если вы выяснили, находится ли конкретная активность в forground и если вы SDK без прямого доступа к Приложению. Для меня я был в фоновом потоке, только что получил push-уведомление о новом сообщении чата и хочу отображать системное уведомление, только если экран чата не находится на переднем плане.
Используя это ActivityLifecycleCallbacks, как было рекомендовано в других ответах, я создал небольшой класс утилит, в котором содержится логика того, MyActivityнаходится ли на переднем плане или нет.
classMyActivityMonitor(context:Context):Application.ActivityLifecycleCallbacks{privatevar isMyActivityInForeground =false
init {(context.applicationContext asApplication).registerActivityLifecycleCallbacks(this)}
fun isMyActivityForeground()= isMyActivityInForeground
override fun onActivityPaused(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =false}}override fun onActivityResumed(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =true}}
И читайте это в другом месте, когда это необходимо,
// Show a Toast Notification if App is not visible (ie in background. Not running, etc) SharedPreferences sharedPrefs =PreferenceManager.getDefaultSharedPreferences(context);if(!sharedPrefs.getBoolean("visible",true)){...}
Может быть, не элегантно, но это работает для меня ...
Возможно, будет слишком поздно, чтобы ответить, но если кто-то приходит в гости, то вот решение, которое я предлагаю: причина (ы), по которой приложение хочет знать, что он находится в фоновом режиме или выходит на передний план, может быть много, некоторые из них 1. Показывать тосты и уведомления, когда пользователь находится в BG. 2. Для выполнения некоторых задач пользователь впервые приходит из BG, например, опрос, перерисовка и т. Д.
Решение от Idolon и других заботится о первой части, но не о второй. Если в вашем приложении есть несколько действий, и пользователь переключается между ними, то к тому времени, когда вы выполняете второе действие, видимый флаг станет ложным. Поэтому его нельзя использовать детерминистически.
Я сделал что-то, что было предложено CommonsWare: «Если Служба определяет, что никаких видимых действий нет, и она остается такой в течение некоторого времени , остановите передачу данных на следующей логической остановке».
Строка, выделенная жирным шрифтом, важна, и ее можно использовать для достижения второго пункта. Так что я делаю, как только я получаю onActivityPaused (), я не изменяю видимое на false напрямую, вместо этого имею таймер в 3 секунды (то есть максимум, что должно быть запущено следующее действие), и если нет onActivityResumed ( ) в течение следующих 3 секунд измените видимость на ложь. Аналогично в onActivityResumed (), если есть таймер, я отменяю его. Подводя итог, видимым становится isAppInBackground.
Я хотел бы рекомендовать вам использовать другой способ сделать это.
Я предполагаю, что вы хотите показать начальный экран во время запуска программы, если она уже запущена в бэкэнде, не показывайте ее.
Ваше приложение может непрерывно записывать текущее время в определенный файл. Когда ваше приложение запускается, проверьте последнюю метку времени, если current_time-last_time> диапазон времени, указанный вами для записи последнего времени, это означает, что ваше приложение остановлено, либо уничтожено системой, либо самим пользователем.
Ответы:
Есть несколько способов определить, работает ли ваше приложение в фоновом режиме, но только один из них является полностью надежным:
Правильное решение (кредиты идут к Дэну , CommonsWare и NeTeInStEiN )
видимости Трек вашего приложения самостоятельно , используя
Activity.onPause
,Activity.onResume
методы. Сохраните статус «видимости» в каком-то другом классе. Хороший выбор - ваша собственная реализацияApplication
или илиService
(есть также несколько вариантов этого решения, если вы хотите проверить видимость активности из службы).Пример
реализации пользовательского
Application
класса (обратите внимание наisActivityVisible()
статический метод):Зарегистрируйте свой класс приложения в
AndroidManifest.xml
:Добавьте
onPause
иonResume
к каждомуActivity
в проекте (вы можете создать общего предка для своих действий, если хотите, но если ваше действие уже расширено изMapActivity
/ListActivity
и т. Д., Вам все еще нужно написать следующее вручную):Обновление
ActivityLifecycleCallbacks было добавлено на уровне API 14 (Android 4.0). Вы можете использовать их, чтобы отслеживать, видна ли активность вашего приложения в данный момент для пользователя. Проверьте ответ Cornstalks ниже для деталей.
Неправильное, которое
я использовал, чтобы предложить следующее решение:
Хотя это решение может работать (и оно действительно работает большую часть времени), я настоятельно рекомендую воздержаться от его использования. И вот почему. Как написала Дайан Хэкборн :
Хотелось бы, чтобы я прочитал это до того, как опубликовал ответ на SO, но, надеюсь, еще не поздно признать мою ошибку.
Другое неправильное решение, которое библиотека
Droid-Fu упоминает в одном из ответов, использует
ActivityManager.getRunningTasks
для своегоisApplicationBroughtToBackground
метода. Посмотрите комментарий Дайанны выше и тоже не используйте этот метод.источник
OnStop
запросуisActivityVisible
.НЕ ИСПОЛЬЗУЙТЕ ЭТО ОТВЕТ
Ответ user1269737 - правильный (одобренный Google / Android) способ сделать это . Идите, прочитайте их ответ и дайте им +1.
Я оставлю свой оригинальный ответ здесь ради потомков. Это было лучшее из доступных в 2012 году, но теперь Android имеет соответствующую поддержку для этого.
Оригинальный ответ
Ключ использует
ActivityLifecycleCallbacks
(обратите внимание, что для этого требуется Android API уровня 14 (Android 4.0)). Просто проверьте, равно ли количество остановленных действий количеству запущенных действий. Если они равны, ваша заявка в фоновом режиме. Если есть еще запущенные действия, ваше приложение все еще отображается. Если действия возобновлены, а не приостановлены, приложение не только отображается, но и на переднем плане. Существуют 3 основных состояния, в которых ваша деятельность может находиться, затем: видимая и на переднем плане, видимая, но не на переднем плане, и не видимая и не на переднем плане (то есть на заднем плане).Отличная вещь в этом методе состоит в том, что он не имеет асинхронных проблем
getRunningTasks()
, но вам также не нужно изменять всеActivity
в вашем приложении для установки / сброса чего-либо вonResumed()
/onPaused()
. Это всего лишь несколько строк кода, которые самодостаточны и работают во всем приложении. Плюс, здесь нет никаких фанки-разрешений.MyLifecycleHandler.java:
MyApplication.java:
@Mewzer задал несколько хороших вопросов об этом методе, на которые я хотел бы ответить в этом ответе для всех:
onStop()
не вызывается в ситуациях с нехваткой памяти; это проблема здесь?Нет, документы
onStop()
говорят:Ключевым моментом здесь является «поддерживать процесс вашей активности …». Если эта ситуация с нехваткой памяти когда-либо будет достигнута, ваш процесс фактически будет уничтожен (а не только ваша активность). Это означает, что этот метод проверки на фоновую целостность все еще действителен, потому что а) вы все равно не можете проверить фоновую обработку, если ваш процесс убит, и б) если ваш процесс запускается снова (потому что создается новое действие), член переменные (статические или нет) для
MyLifecycleHandler
будут сброшены в0
.Это работает для изменений конфигурации?
По умолчанию нет. Вы должны явно указать
configChanges=orientation|screensize
(|
со всем, что хотите) в файле манифеста и обработать изменения конфигурации, иначе ваша деятельность будет уничтожена и воссоздана. Если вы не установили это, методы вашей деятельности будет называться в следующем порядке:onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. Как видите, перекрытия нет (как правило, при переключении между двумя действиями очень кратко перекрываются два действия, как работает этот метод обнаружения фона). Для того, чтобы обойти это, вы должны установить,configChanges
чтобы ваша деятельность не была разрушена. К счастью, мне пришлось установитьconfigChanges
уже во всех моих проектах, потому что было нежелательно, чтобы вся моя деятельность разрушалась при повороте / изменении размера экрана, поэтому я никогда не считал это проблематичным. (спасибо dpimka за то, что освежил мою память об этом и исправил меня!)Одна запись:
Когда я сказал «фон» в этом ответе, я имел в виду «ваше приложение больше не видно». Действия Android могут быть видны, но не на переднем плане (например, если есть прозрачное наложение уведомлений). Вот почему я обновил этот ответ, чтобы отразить это.
Важно знать, что у Android есть странный подвешенный момент при переключении действий, когда ничто не находится на переднем плане . По этой причине, если вы проверяете, находится ли ваше приложение на переднем плане при переключении между действиями (в том же приложении), вам будет сказано, что вы не на переднем плане (даже если ваше приложение все еще является активным приложением и отображается ).
Вы можете проверить , если ваше приложение находится на переднем плане в вашей
Activity
«SonPause()
метод послеsuper.onPause()
. Просто вспомните странное состояние неопределенности, о котором я только что говорил.Вы можете проверить , если ваше приложение видимое (то есть , если это не в фоновом режиме) в вашем
Activity
«SonStop()
методе послеsuper.onStop()
.источник
onStop()
послеsuper.onStop()
. Не проверяйте фоновый режим вonPause()
.РЕШЕНИЕ GOOGLE - не хак, как предыдущие решения. Используйте ProcessLifecycleOwner
Kotlin:
Ява:
в приложении
Вы можете прочитать больше о компонентах архитектуры, связанных с жизненным циклом, здесь - https://developer.android.com/topic/libraries/architecture/lifecycle
источник
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
тогда вы можете получить состояние переднего плана сArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, это не работает дляmultiple processes
приложений, есть ли какой-нибудь API, который мы можем достичь элегантно?Начиная с версии 26 библиотеки поддержки, вы можете использовать ProcessLifecycleOwner , просто добавьте его в свою зависимость, как описано здесь , например:
А затем просто запрашивайте в
ProcessLifecycleOwner
любое время состояние приложения, примеры:источник
Начиная с Android API 16 существует простой способ проверить, находится ли приложение на переднем плане. Это может быть небезопасно, но никакие методы на Android не являются надежными. Этот метод достаточно хорош для использования, когда ваша служба получает обновление от сервера и должна решить, показывать уведомление или нет (потому что, если пользовательский интерфейс находится на переднем плане, пользователь заметит обновление без уведомления).
источник
JobService
чтобы обнаружить, что служба работает в фоновом режиме.Ответ Идолона подвержен ошибкам и гораздо более сложный, хотя повторять здесь проверить приложение для Android на переднем плане или нет? и тут Определение текущего приоритетного приложения из фоновой задачи или службы
Существует гораздо более простой подход:
На BaseActivity, что все действия расширяются:
Всякий раз, когда вам нужно проверить, находится ли какое-либо из ваших действий приложения на переднем плане, просто проверьте
isVisible()
;Чтобы понять этот подход, проверьте ответ «жизненный цикл параллельной деятельности»: жизненный цикл активности
источник
Idolon's answer is error prone
- к сожалению, я должен согласиться с вами. На основании комментария Дайан Хэкборн в группах Google я обновил свой ответ. Проверьте это, пожалуйста, для деталей.onPause
,onStop
, ниonResume
событие называется. Так что же делать, если ни одно из этих событий не запущено ?!Я попытался рекомендовать решение, которое использует Application.ActivityLifecycleCallbacks и многие другие, но они не сработали, как ожидалось. Благодаря Sarge я нашел довольно простое и понятное решение, которое я описываю ниже.
Это также основная разница между
onStop()
иonPause()
что никто не сделал упоминания в статьях , которые я прочитал.Таким образом, основываясь на поведении этого жизненного цикла, вы можете просто посчитать, сколько раз это делали
onStart()
иonPause()
вызывали в вашей программе. Обратите внимание, что для каждойActivity
вашей программы вы должны переопределитьonStart()
иonStop()
, чтобы увеличить / уменьшить статическую переменную, используемую для подсчета. Ниже приведен код, реализующий эту логику. Обратите внимание, что я использую класс, который расширяетсяApplication
, поэтому не забудьте объявитьManifest.xml
внутри тега Application:android:name=".Utilities"
хотя он также может быть реализован с использованием простого пользовательского класса.Теперь в каждом действии нашей программы мы должны переопределять
onStart()
иonStop()
и увеличивать / уменьшать, как показано ниже:С этой логикой, есть 2 возможных случая:
stateCounter = 0
: Количество остановленных равно количеству запущенных операций, что означает, что приложение работает в фоновом режиме.stateCounter > 0
: Количество запущенных больше, чем количество остановленных, что означает, что приложение работает на переднем плане.Обратите внимание:
stateCounter < 0
будет означать, что больше остановленных действий, чем начатых, что невозможно. Если вы столкнулись с этим случаем, это означает, что вы не увеличиваете / уменьшаете счетчик, как следует.Вы готовы к работе. Вы должны проверить, находится ли ваше приложение на заднем плане внутри
onStop()
.источник
if(Utilities.isApplicationOnBackground()) …
вUtilities
. Потому что в противном случае только конкретное действие будет реагировать на событие.Нет способа, если вы не отслеживаете это самостоятельно, чтобы определить, являются ли какие-либо из ваших действий видимыми или нет. Возможно, вам следует подумать о том, чтобы задать новый вопрос StackOverflow, объяснив, чего вы пытаетесь добиться от взаимодействия с пользователем, чтобы мы могли предложить вам альтернативные идеи реализации.
источник
Service
. Если это так, попросите службу уведомить службу по мере их появления и исчезновения. ЕслиService
выясняется, что никаких видимых действий нет, и он остается таким в течение некоторого времени, остановите передачу данных в следующей точке логического останова. Да, для этого потребуется код для каждого из ваших действий, но сейчас это неизбежно, AFAIK.MyActivityClass
наследующийActivity
и реализующий методы жизненного цикла, и сделать все ваши действия наследуемымиMyActivityClass
. Это не будет работать дляPreferenceActivity
илиMapActivity
хотя (см. Этот вопрос )Вы можете использовать ComponentCallbacks2, чтобы определить, находится ли приложение в фоновом режиме. Кстати, этот обратный вызов доступен только в API Level 14 (Ice Cream Sandwich) и выше.
Вы получите вызов метода:
public abstract void onTrimMemory (int level)
если уровень -
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
приложение в фоновом режиме.Вы можете реализовать этот интерфейс
activity
,service
и т. Д.источник
Опираясь на @Cornstalks ответ, чтобы включить несколько полезных функций.
Дополнительные функции:
App.java
AppLifecycleHandler.java
источник
Лучшее решение, которое я придумал, использует таймеры.
Вы запускаете таймер в onPause () и отменяете тот же таймер в onResume (), есть 1 экземпляр Timer (обычно определяется в классе Application). Сам таймер настроен на запуск Runnable через 2 секунды (или любой интервал, который вы считаете подходящим), когда срабатывает таймер, вы устанавливаете флаг, отмечающий приложение как фоновое.
В методе onResume () перед отменой таймера можно запросить флаг фона для выполнения любых операций запуска (например, начать загрузку или включить службы определения местоположения).
Это решение позволяет выполнять несколько операций в заднем стеке и не требует каких-либо разрешений для реализации.
Это решение хорошо работает, если вы также используете шину событий, поскольку ваш таймер может просто инициировать событие, и различные части вашего приложения могут реагировать соответствующим образом.
источник
Если вы включите настройки разработчика «Не сохранять активности» - проверьте, что количество созданных активностей недостаточно. Вы должны проверить также isSaveInstanceState . Мой пользовательский метод isApplicationRunning () проверяет, запущено ли приложение для Android:
Вот мой рабочий код:
источник
Единственное правильное решение:
MainActivity.java:
MyApp.java:
источник
Чтобы прокомментировать сказанное в CommonsWare и Key, вы можете расширить класс Application и сделать так, чтобы все ваши действия вызывали его в своих методах onPause / onResume. Это позволит вам узнать, какие виды деятельности видны, но, вероятно, это можно сделать лучше.
Можете ли вы уточнить, что именно вы имеете в виду? Когда вы говорите, что работаете в фоновом режиме, вы подразумеваете, что ваше приложение все еще находится в памяти, хотя его нет на экране? Рассматривали ли вы использование Сервисов как более устойчивый способ управления вашим приложением, когда оно не в фокусе?
источник
Application
не имеетonPause()
илиonResume()
.Я сделал свою собственную реализацию ActivityLifecycleCallbacks. Я использую SherlockActivity, но для обычного класса Activity может работать.
Во-первых, я создаю интерфейс, который имеет все методы для отслеживания жизненного цикла действий:
Во-вторых, я реализовал этот интерфейс в классе моего приложения:
В-третьих, я создаю класс, который выходит из SherlockActivity:
В-четвертых, все классы, которые выходят из SherlockActivity, я заменил на MySherlockActivity:
Теперь в logcat вы увидите логи, запрограммированные в реализации интерфейса, выполненной в MyApplication.
источник
Активность приостанавливается, когда над ним появляется диалог, поэтому все рекомендуемые решения являются полурешениями. Вам также необходимо создать хуки для диалогов.
источник
Поскольку это еще не упомянуто, я предлагаю читателям изучить ProcessLifecycleOwner, доступный через компоненты архитектуры Android.
источник
Официальные документы:
Система различает фоновые и фоновые приложения. (Определение фона для целей ограничения услуг отличается от определения, используемого управлением памятью; приложение может находиться в фоновом режиме в том, что касается управления памятью , но на переднем плане - в отношении его способности запускать службы.) считается находящимся на переднем плане, если выполняется любое из следующих условий:
Если ни одно из этих условий не выполняется, приложение считается в фоновом режиме.
источник
Другое решение для этого старого поста (для тех, которые могут помочь):
источник
Смотрите комментарий в функции onActivityDestroyed.
Работает с целевой версией SDK 14>:
источник
Вы должны использовать общие предпочтения для хранения собственности и действовать в соответствии с ней, используя привязку сервисов из ваших действий. Если вы используете только привязку (то есть никогда не используете startService), то ваша служба будет работать только при привязке к ней (привязка onResume и unbind onPause), что заставит ее работать только на переднем плане, и если вы захотите работать с ней. В фоновом режиме вы можете использовать обычную службу начала остановки.
источник
Я думаю, что этот вопрос должен быть более ясным. Когда? Куда? Какова ваша конкретная ситуация, которую вы хотите знать, если ваше приложение в фоновом режиме?
Я просто представляю свое решение по-своему.
Для этого я использую поле «важность»
RunningAppProcessInfo
класса вonStop
методе каждого действия в моем приложении, чего можно добиться, просто предоставивBaseActivity
расширение для других действий, которое реализуетonStop
метод для проверки значения «важность». Вот код:источник
Я рекомендую прочитать эту страницу: http://developer.android.com/reference/android/app/Activity.html.
Короче говоря, ваша активность больше не видна после
onStop()
вызова.источник
onStop
; междуonPause
иonStop
это видно , но не на переднем плане .onStop()
, которая соответствует тому, что вы написали.onPause
не называется: недавнее редактирование исправило вас.Как насчет использования getApplicationState (). IsInForeground ()?
источник
По моему мнению, многие ответы вводят большую нагрузку кода и приносят много сложности и нечитаемости.
Когда люди спрашивают на SO, как общаться между a
Service
и aActivity
, я обычно советую использовать LocalBroadcastManager .Зачем?
Ну, цитируя документы:
Не в документах:
Activity
,Application
...Описание
Итак, вы хотите проверить, находится ли какая-либо из
Activity
них на переднем плане. Вы обычно делаете это в классеService
или в своемApplication
классе.Это означает, что ваши
Activity
объекты становятся отправителями сигнала (я включен / выключен). ВашService
, с другой стороны, становитсяReceiver
.Есть два момента, в которых ваш
Activity
говорит вам, идет ли он на переднем плане или на заднем плане (да только два ... не 6).Когда
Activity
выходит на передний план,onResume()
метод срабатывает (также вызывается послеonCreate()
).Когда
Activity
идет в спину,onPause()
называется.Это моменты, в которые вы
Activity
должны послать свой сигнал,Service
чтобы описать его состояние.В случае нескольких
Activity
, помнитеActivity
вначале уходит на задний план, затем на передний план выходит другой.Так что ситуация будет такой: *
Service
/Application
Будет просто продолжать слушать музыку этих сигналов и действовать соответствующим образом .Код (TLDR)
Вы
Service
должны реализовать дляBroadcastReceiver
того, чтобы слушать сигналы.Зарегистрируйся
Receiver
вService::onCreate()
Отменить регистрацию в
Service::onDestroy()
Теперь вы
Activity
должны сообщить свое состояние.В
Activity::onResume()
В
Activity::onPause()
Очень, очень распространенная ситуация
Обычно нет необходимости проверять,
Activity
находится ли на переднем плане или нет. Просто отправьте данные черезLocalBroadcastManager
вашService
. ЕслиActivity
он включен, он будет реагировать и действовать.В этой очень распространенной ситуации
Service
становится отправителем, аActivity
реализуетBroadcastReceiver
.Итак, создайте
Receiver
в своемActivity
. Зарегистрируйте этоonResume()
и отмените регистрацию вonPause()
. Нет необходимости использовать другие методы жизненного цикла .Определите
Receiver
поведение вonReceive()
(обновите ListView, сделайте это, сделайте это, ...).Таким образом, он
Activity
будет слушать только если он находится на переднем плане и ничего не произойдет, если он находится сзади или уничтожен.В случае нескольких
Activity
,Activity
ответ будет зависеть (если они также реализуютReceiver
).Если все на заднем плане, никто не ответит, и сигнал просто потеряется.
Отправьте данные
Service
через каналIntent
(см. Код выше), указав идентификатор сигнала.источник
источник
Ни один из ответов не вполне соответствовал конкретному случаю, если вы выяснили, находится ли конкретная активность в forground и если вы SDK без прямого доступа к Приложению. Для меня я был в фоновом потоке, только что получил push-уведомление о новом сообщении чата и хочу отображать системное уведомление, только если экран чата не находится на переднем плане.
Используя это
ActivityLifecycleCallbacks
, как было рекомендовано в других ответах, я создал небольшой класс утилит, в котором содержится логика того,MyActivity
находится ли на переднем плане или нет.}
источник
В моих действиях onResume и onPause я записываю логическое значение isVisible для SharedPrefences.
И читайте это в другом месте, когда это необходимо,
Может быть, не элегантно, но это работает для меня ...
источник
Возможно, будет слишком поздно, чтобы ответить, но если кто-то приходит в гости, то вот решение, которое я предлагаю: причина (ы), по которой приложение хочет знать, что он находится в фоновом режиме или выходит на передний план, может быть много, некоторые из них 1. Показывать тосты и уведомления, когда пользователь находится в BG. 2. Для выполнения некоторых задач пользователь впервые приходит из BG, например, опрос, перерисовка и т. Д.
Решение от Idolon и других заботится о первой части, но не о второй. Если в вашем приложении есть несколько действий, и пользователь переключается между ними, то к тому времени, когда вы выполняете второе действие, видимый флаг станет ложным. Поэтому его нельзя использовать детерминистически.
Я сделал что-то, что было предложено CommonsWare: «Если Служба определяет, что никаких видимых действий нет, и она остается такой в течение некоторого времени , остановите передачу данных на следующей логической остановке».
Строка, выделенная жирным шрифтом, важна, и ее можно использовать для достижения второго пункта. Так что я делаю, как только я получаю onActivityPaused (), я не изменяю видимое на false напрямую, вместо этого имею таймер в 3 секунды (то есть максимум, что должно быть запущено следующее действие), и если нет onActivityResumed ( ) в течение следующих 3 секунд измените видимость на ложь. Аналогично в onActivityResumed (), если есть таймер, я отменяю его. Подводя итог, видимым становится isAppInBackground.
Извините не могу скопировать и вставить код ...
источник
Я хотел бы рекомендовать вам использовать другой способ сделать это.
Я предполагаю, что вы хотите показать начальный экран во время запуска программы, если она уже запущена в бэкэнде, не показывайте ее.
Ваше приложение может непрерывно записывать текущее время в определенный файл. Когда ваше приложение запускается, проверьте последнюю метку времени, если current_time-last_time> диапазон времени, указанный вами для записи последнего времени, это означает, что ваше приложение остановлено, либо уничтожено системой, либо самим пользователем.
источник