Что касается фона, я имею в виду, что ни один из действий приложения в настоящее время не отображается пользователю?
Проверка, работает ли приложение Android в фоновом режиме
Ответ 1
Существует несколько способов определить, работает ли ваше приложение в фоновом режиме, но только один из них является полностью надежным:
-
Правильное решение (кредиты идут Dan, CommonsWare и NeTeInStEiN)
Просматривайте видимость своего приложения самостоятельно, используя методыActivity.onPause
,Activity.onResume
. Сохранять статус "видимости" в каком-либо другом классе. Хороший выбор - это ваша собственная реализацияApplication
илиService
(есть также несколько вариантов этого решения, если вы хотите проверить активность активности от услуга).
Пример
Внедрение пользовательского классаApplication
(обратите внимание на статический методisActivityVisible()
):public class MyApplication extends Application { public static boolean isActivityVisible() { return activityVisible; } public static void activityResumed() { activityVisible = true; } public static void activityPaused() { activityVisible = false; } private static boolean activityVisible; }
Зарегистрируйте свой класс приложения в
AndroidManifest.xml
:<application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" >
Добавьте
onPause
иonResume
в каждыйActivity
в проекте (вы можете создать общий предок для своих действий, если хотите, но если ваша активность уже расширена сMapActivity
/ListActivity
и т.д. вам все равно нужно написать следующее вручную):@Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); }
Обновление
ActivityLifecycleCallbacks были добавлены на уровне API 14 (Android 4.0). Вы можете использовать их для отслеживания активности пользователя вашего приложения в данный момент. Ответьте ответ на вопрос кукурузы ниже. -
Неверный
Я предлагал следующее решение:Вы можете обнаружить в настоящее время приложение foreground/background с
ActivityManager.getRunningAppProcesses()
, которое возвращает список записейRunningAppProcessInfo
. Чтобы определить, находится ли ваше приложение на переднем плане, проверьтеRunningAppProcessInfo.importance
поле для равенства сRunningAppProcessInfo.IMPORTANCE_FOREGROUND
, аRunningAppProcessInfo.processName
равно имени вашего пакета приложений.Также, если вы вызываете
ActivityManager.getRunningAppProcesses()
из потока пользовательского интерфейса приложения, он вернет важностьIMPORTANCE_FOREGROUND
для вашей задачи независимо от того, действительно ли она находится на переднем плане или нет. Вызовите его в фоновом потоке (например, черезAsyncTask
), и он вернет правильные результаты.Хотя это решение может работать (и оно действительно работает большую часть времени), я настоятельно рекомендую воздержаться от его использования. И вот почему. Как пишет Dianne Hackborn:
Эти API-интерфейсы не существуют для приложений, на которых основывается их поток пользовательского интерфейса, но чтобы делать такие вещи, как показывать пользователям запущенные приложения или диспетчер задач или такие.
Да, есть список, хранящийся в памяти для этих вещей. Тем не менее, он отключен в другом процессе, управляемом потоками, выполняемыми отдельно от вашего, а не тем, на что вы можете рассчитывать (a) своевременно видеть правильное решение или (b) иметь согласованное изображение к моменту вашего возвращения. Плюс решение о том, что нужно делать "следующей" активности, всегда выполняется в точке, где должен произойти переход, и только до этой точки (где состояние активности ненадолго заблокировано, чтобы сделать переключатель), что мы на самом деле точно знаю, что будет дальше.
И реализация и глобальное поведение здесь не гарантируются, что они останутся прежними в будущем.
Хотелось бы, чтобы я прочитал это, прежде чем отправил ответ на SO, но надеюсь, что не поздно признать мою ошибку.
-
Другое неправильное решение
Droid-Fu библиотека, упомянутая в одном из ответов, используетActivityManager.getRunningTasks
для своего методаisApplicationBroughtToBackground
. См. Комментарий Dianne выше и не используйте этот метод.
Ответ 2
НЕ ИСПОЛЬЗУЙТЕ ЭТО ОТВЕТ
user1269737 - это правильный (одобренный Google/Android) способ сделать это. Прочитайте их ответ и дайте им +1.
Я оставлю свой оригинальный ответ здесь ради потомков. Это было лучшее из доступных в 2012 году, но теперь Android имеет соответствующую поддержку для этого.
Оригинальный ответ
Ключ использует ActivityLifecycleCallbacks
(обратите внимание, что для этого требуется Android API уровня 14 (Android 4.0)). Просто проверьте, равно ли количество остановленных действий количеству запущенных действий. Если они равны, ваша заявка в фоновом режиме. Если есть еще запущенные действия, ваше приложение все еще отображается. Если действия возобновлены, а не приостановлены, приложение не только отображается, но и на переднем плане. Существуют 3 основных состояния, в которых ваша деятельность может находиться, затем: видимая и на переднем плане, видимая, но не на переднем плане, и не видимая и не на переднем плане (т.е. на заднем плане).
getRunningTasks()
вещь в этом методе состоит в том, что у него нет асинхронных проблем, getRunningTasks()
делает getRunningTasks()
, но вам также не нужно изменять каждую Activity
в вашем приложении, чтобы устанавливать /onResumed()
что-то в onResumed()
/onPaused()
. Это всего лишь несколько строк кода, которые самодостаточны и работают во всем приложении. Плюс, здесь нет никаких фанки-разрешений.
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// 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.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void 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" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that 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(new MyLifecycleHandler());
}
}
@Mewzer задал несколько хороших вопросов об этом методе, на которые я хотел бы ответить в этом ответе для всех:
onStop()
не вызывается в ситуациях с onStop()
памяти; это проблема здесь?
Нет. Документы для onStop()
говорят:
Обратите внимание, что этот метод никогда не может быть вызван в ситуациях нехватки памяти, когда системе не хватает памяти, чтобы поддерживать процесс активности после вызова метода onPause().
Ключевым моментом здесь является "поддерживать процесс активности...". Если ситуация с нехваткой памяти когда-либо будет достигнута, ваш процесс фактически будет уничтожен (а не только ваша активность). Это означает, что этот метод проверки на фоновую целостность все еще действителен, потому что а) вы все равно не можете проверить фоновую обработку, если ваш процесс убит, и б) если ваш процесс запускается снова (потому что создается новое действие), член переменные (статические или нет) для MyLifecycleHandler
будут сброшены в 0
.
Это работает для изменения конфигурации?
По умолчанию нет. Вы должны явно установить configChanges=orientation|screensize
(|
с чем-либо еще) в вашем файле манифеста и обрабатывать изменения конфигурации, иначе ваша деятельность будет уничтожена и воссоздана. Если вы не установите это, ваши методы деятельности будут вызываться в следующем порядке: onCreate → onStart → onResume → (now rotate) → onPause → onStop → onDestroy → onCreate → onStart → onResume
. Как видите, перекрытия нет (как правило, при переключении между двумя действиями очень кратко перекрываются два действия, как работает этот метод обнаружения фона). Чтобы обойти это, вы должны установить configChanges
чтобы ваша деятельность не была уничтожена. К счастью, мне приходилось устанавливать configChanges
уже во всех моих проектах, потому что было нежелательно, чтобы вся моя деятельность разрушалась при повороте/изменении размера экрана, поэтому я никогда не считал это проблематичным. (спасибо dpimka за то, что освежил мою память об этом и исправил меня!)
Одна запись:
Когда я сказал "фон" в этом ответе, я имел в виду "ваше приложение больше не видно". Действия Android могут быть видны еще не на переднем плане (например, если есть прозрачное наложение уведомлений). Вот почему я обновил этот ответ, чтобы отразить это.
Важно знать, что у Android есть странный подвешенный момент при переключении действий, когда ничто не находится на переднем плане. По этой причине, если вы проверяете, находится ли ваше приложение на переднем плане при переключении между действиями (в том же приложении), вам будет сказано, что вы не на переднем плане (даже если ваше приложение все еще является активным приложением и отображается).
Вы можете проверить, находится ли ваше приложение на переднем плане в вашем onPause()
Activity
onPause()
после super.onPause()
. Просто вспомните странное состояние неопределенности, о котором я только что говорил.
Вы можете проверить, является ли ваше приложение видимым (то есть, если оно не в фоновом режиме) в вашем onStop()
Activity
onStop()
после super.onStop()
.
Ответ 3
РЕШЕНИЕ GOOGLE - не хак, как предыдущие решения. Используйте ProcessLifecycleOwner
Kotlin:
class ArchLifecycleApp : 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
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
в app.gradle
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' }
}
}
Вы можете узнать больше о компонентах архитектуры, связанных с жизненным циклом, здесь - https://developer.android.com/topic/libraries/architecture/lifecycle
Ответ 4
Ответ на Idolon является склонным к ошибкам и гораздо более сложным, хотя здесь повторяется проверить приложение Android на переднем плане или нет? и здесь Определение текущего приложения переднего плана из фоновой задачи или службы
Существует гораздо более простой подход:
В BaseActivity все действия расширяются:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
Всякий раз, когда вам нужно проверить , если какая-либо из ваших приложений работает на переднем плане, просто проверьте isVisible()
;
Чтобы понять этот подход, проверьте этот ответ о жизненном цикле действий "бок о бок": Жизненный цикл активности бок о бок
Ответ 5
Начиная с версии 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 background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Ответ 6
Так как Android API 16 есть простой способ проверить, находится ли приложение на переднем плане. Он не может быть надежным, но никакие методы на Android не являются надежными. Этот метод достаточно хорош для использования, когда ваша служба получает обновление с сервера и должна решить, показывать ли уведомление или нет (потому что если пользовательский интерфейс является приоритетным, пользователь заметит обновление без уведомления).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Ответ 7
Я попробовал рекомендованное решение, которое использует Application.ActivityLifecycleCallbacks и многие другие, но они не работали должным образом. Благодаря Sarge я придумал довольно легкое и простое решение, которое я описываю ниже.
Ключом решения является факт понимания того, что если у нас есть ActivityA и ActivityB, и мы вызываем ActivityB из ActivityA (и не вызываем
ActivityA.finish
), тогда ActivityBonStart()
будет называться до ActivityAonStop()
.
Это также основная разница между onStop()
и onPause()
, о которой никто не упоминал в прочитанных статьях.
Итак, основываясь на этом жизненном цикле активности, вы можете просто подсчитать, сколько раз вызывали в вашей программе onStart()
и onPause()
. Обратите внимание, что для каждой Activity
вашей программы вы должны переопределить onStart()
и onStop()
, чтобы увеличить/уменьшить статическую переменную, используемую для подсчета. Ниже приведен код, реализующий эту логику. Обратите внимание, что я использую класс, который расширяет Application
, поэтому не забывайте объявлять на Manifest.xml
внутри тега приложения: android:name=".Utilities"
, хотя он также может быть реализован с помощью простого пользовательского класса.
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
Теперь в каждом действии нашей программы мы должны переопределить onStart()
и onStop()
и приращение/декремент, как показано ниже:
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
С этой логикой возможны два случая:
-
stateCounter = 0
: количество остановленных равно количеству запущенных действий, что означает, что приложение работает на фоне. -
stateCounter > 0
: число запусков больше, чем количество остановленных, что означает, что приложение работает на переднем плане.
Примечание: stateCounter < 0
означает, что больше остановлено действие, чем начато, что невозможно. Если вы столкнулись с этим случаем, это означает, что вы не увеличиваете/уменьшаете счетчик, как вам следует.
Вы готовы к работе. Вы должны проверить, находится ли ваше приложение на фоне внутри onStop()
.
Ответ 8
Нет никакого способа, чтобы вы сами отслеживали его, чтобы определить, видны ли какие-либо из ваших действий или нет. Возможно, вам стоит рассмотреть вопрос о новом вопросе StackOverflow, объяснив, что именно вы пытаетесь достичь из пользовательского опыта, поэтому мы можем дать вам альтернативные идеи реализации.
Ответ 9
Вы можете использовать ComponentCallbacks2, чтобы определить, находится ли приложение в фоновом режиме. Кстати, этот обратный вызов доступен только в API уровня 14 (Ice Cream Sandwich) и выше.
Вы получите вызов метода:
public abstract void onTrimMemory (int level)
если уровень - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
то приложение находится в фоновом режиме.
Вы можете реализовать этот интерфейс для activity
, service
и т.д.
public class MainActivity extends AppCompatActivity 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) {
// app is in background
}
}
}
Ответ 10
Основываясь на @Cornstalks, ответьте на несколько полезных функций.
Дополнительные функции:
- введен одиночный шаблон, поэтому вы можете сделать это в любом месте приложения: AppLifecycleHandler.isApplicationVisible() и AppLifecycleHandler.isApplicationInForeground()
- добавлена обработка повторяющихся событий (см. комментарии//предпринимаем некоторые действия по изменению видимости и//предпринимаем некоторые действия по изменению на переднем плане)
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
Ответ 11
Лучшее решение, которое я придумал, использует таймеры.
Вы запустили таймер в onPause() и отменили тот же таймер в onResume(), есть 1 экземпляр таймера (обычно определенный в классе Application). Сам таймер настроен на запуск Runnable через 2 секунды (или какой-либо промежуток, который, по вашему мнению, подходит), когда срабатывает таймер, вы устанавливаете флаг, обозначающий приложение как находящееся в фоновом режиме.
В методе onResume() перед отменой таймера вы можете запросить флаг фона для выполнения любых операций запуска (например, начать загрузку или включить службы определения местоположения).
Это решение позволяет вам иметь несколько действий в фоновом стеке и не требует каких-либо разрешений для реализации.
Это решение работает хорошо, если вы также используете шину событий, так как ваш таймер может просто запустить событие, и различные части вашего приложения могут соответственно реагировать.
Ответ 12
Если вы включите настройки разработчика "Не держите акты" - проверьте только количество созданных действий недостаточно. Вы также должны проверить isSaveInstanceState. Мой пользовательский метод isApplicationRunning() проверяет приложение для Android:
Здесь мой код работы:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
Ответ 13
Чтобы скомпилировать то, что сказали CommonsWare и Key, возможно, вы можете расширить класс Application и задействовать все ваши действия в своих методах onPause/onResume. Это позволит вам узнать, какие действия видны, но с этим, вероятно, можно будет справиться лучше.
Можете ли вы подробно рассказать о том, что вы имеете в виду? Когда вы говорите, что работаете в фоновом режиме, вы имеете в виду просто наличие вашего приложения в памяти, даже если оно не отображается на экране? Вы изучали использование служб как более постоянный способ управления своим приложением, когда он не находится в фокусе?
Ответ 14
Я сделал свою собственную реализацию ActivityLifecycleCallbacks. Я использую SherlockActivity, но для нормального класса Activity может работать.
Во-первых, я создаю интерфейс, который имеет все методы для отслеживания жизненного цикла действий:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
Во-вторых, я реализовал этот интерфейс в своем классе Application:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
В-третьих, я создаю класс, который простирается от SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
В-четвертых, все классы, которые простираются от SherlockActivity, я заменил для MySherlockActivity:
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Теперь в logcat вы увидите журналы, запрограммированные в реализации интерфейса, выполненные в MyApplication.
Ответ 15
Активность приостанавливается, когда Dialog выходит за нее, поэтому все рекомендуемые решения являются полурешениями. Вам также нужно создать крючки для диалогов.
Ответ 16
Поскольку он еще не упоминается, я предлагаю читателям изучить ProcessLifecycleOwner через компоненты Android Architecture
Ответ 17
Система отличает приложения для переднего и заднего плана. (Определение фона для целей ограничения обслуживания отличается от определения, используемого управлением памятью, приложение может быть в фоновом режиме, как относится к управлению памятью, но на переднем плане, как и его способность к запуск приложений.) Приложение считается на переднем плане, если выполняется одно из следующих условий:
- Он имеет видимую активность, запускается или приостанавливается действие.
- У него есть функция переднего плана.
- Другое приложение переднего плана подключается к приложению либо путем привязки к одному из его сервисов, либо путем использования одного из его поставщиков контента. Например, приложение находится на переднем плане, если другое приложение привязывается к его:
- IME
- Обои для рабочего стола
- Слушатель уведомлений
- Голосовое или текстовое обслуживание
Если ни одно из этих условий не является истинным, приложение считается фоновым.
Ответ 18
Единственное правильное решение:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
MyApp.java:
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
Ответ 19
Я рекомендую прочитать эту страницу: http://developer.android.com/reference/android/app/Activity.html
Короче говоря, ваша активность больше не видна после вызова onStop()
.
Ответ 20
Другое решение для этого старого сообщения (для тех, которые могут помочь):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
Ответ 21
См. комментарий в функции onActivityDestroyed.
Работает с целевой версией SDK 14 > :
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
Ответ 22
Вы должны использовать общее предпочтение для хранения свойства и действовать с ним, используя привязку к сервису из ваших действий. Если вы используете привязку только (которая никогда не использует startService), ваша служба будет работать только при ее привязке (bind onResume и unbind onPause), которая заставит ее работать только на переднем плане, и если вы хотите работать фон, вы можете использовать обычную службу остановки запуска.
Ответ 23
Я думаю, что этот вопрос должен быть более ясным. Когда? Где? Какова ваша конкретная ситуация, которую вы хотите создать, если ваше приложение находится в фоновом режиме?
Я просто представляю свое решение на моем пути.
Я делаю это, используя поле "важность" класса RunningAppProcessInfo
в каждом действии onStop
в моем приложении, которое может быть просто достигнуто путем предоставления BaseActivity
для других действий, которые расширяются, что реализует метод onStop
для проверки значения "важности". Вот код:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
Ответ 24
Как использовать getApplicationState(). isInForeground()?
Ответ 25
На мой взгляд, многие ответы вводят большую нагрузку кода и приносят большую сложность и не читаемость.
Когда люди спрашивают SO, как общаться между Service
и a Activity
, я обычно советю использовать LocalBroadcastManager.
Почему?
Ну, цитируя документы:
Вы знаете, что данные, которые вы передаете, не покидают ваше приложение, поэтому вам не нужно беспокоиться о утечке конфиденциальных данных.
Другие приложения не могут отправлять эти широковещательные передачи в ваше приложение, поэтому вам не нужно беспокоиться о наличии дыр в безопасности, которые они могут использовать.
Это более эффективно, чем отправка глобальной широковещательной передачи через систему.
Не в документах:
- Он не требует внешних библиотек
- Минимальный код
- Быстро реализовать и понять
- Никакие пользовательские самореализованные обратные вызовы/ультра-одиночные/внутрипроцессные шаблон вообще...
- Нет сильных ссылок на
Activity
,Application
,...
Описание
Итак, вы хотите проверить, находится ли какой-либо из Activity
в настоящее время на переднем плане. Обычно вы выполняете это в классе Service
или Application
.
Это означает, что ваши объекты Activity
становятся отправителем сигнала (я нахожусь/я выключен). С другой стороны, ваш Service
становится Receiver
.
Есть моменты два, в которых ваш Activity
говорит вам, идет ли он на переднем плане или в фоновом режиме (да только два... не 6).
Когда Activity
переходит на передний план, запускается метод onResume()
(также называемый после onCreate()
).
Когда Activity
идет в обратном направлении, вызывается onPause()
.
Это моменты, когда ваш Activity
должен отправить сигнал вашему Service
, чтобы описать его состояние.
В случае нескольких Activity
', помните, что a Activity
сначала переходит в фоновый режим, затем на передний план выходит другой.
Итак, ситуация была бы: *
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service
/Application
будет просто продолжать слушать эти сигналы и действовать соответственно.
Код (TL;DR)
Ваш Service
должен реализовать BroadcastReceiver
для прослушивания сигналов.
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Зарегистрируйте Receiver
в Service::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
Отмените регистрацию в Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Теперь ваш Activity
должен сообщить свое состояние.
В Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
В Activity::onPause()
Intent intent = new Intent();
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
(см. код выше), указав идентификатор сигнала.
- За исключением Поддержка нескольких окон. Это может быть сложно (пожалуйста, проверьте его при необходимости)...
Ответ 26
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
Ответ 27
Ни один из ответов не вписывается в конкретный случай, если вам кажется, что вы знаете, находится ли конкретная активность в forground, и если вы SDK без прямого доступа к Приложению. Для меня я был в фоновом потоке, только что получил push-уведомление о новом сообщении чата и хочу отображать системное уведомление, только если экран чата не находится на переднем плане.
Используя ActivityLifecycleCallbacks
, как было рекомендовано в других ответах, я создал небольшой класс утилит, в котором содержится логика того, находится ли MyActivity
на переднем плане или нет.
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
Ответ 28
В моих действиях onResume и onPause я пишу isVisible булевым для SharedPrefences.
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
И прочитайте его в другом месте, когда это необходимо,
// 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)){...}
Возможно, не элегантный, но он работает для меня...
Ответ 29
Может быть, слишком поздно ответить, но если кто-то приходит навестить, то вот решение, которое я предлагаю, Причина (и) приложение хочет знать, что состояние присутствия в фоновом режиме или переход на передний план может быть много, некоторые из них, 1. Чтобы показать тосты и уведомления, когда пользователь находится в BG. 2.Чтобы выполнить некоторые задачи в первый раз, когда пользователь приходит из BG, как опрос, перерисовывает и т.д.
Решение Idolon и других заботится о первой части, но не для второй. Если в вашем приложении есть несколько действий, и пользователь переключается между ними, то к тому моменту, когда вы находитесь во втором действии, видимый флаг будет ложным. Поэтому он не может быть использован детерминистически.
Я сделал что-то, что было предложено CommonsWare: "Если Служба определяет, что видимых действий нет, и остается таким образом в течение некоторого времени, остановите передачу данных в следующем логическом остановка".
Строка, выделенная полужирным шрифтом, важна, и это можно использовать для достижения второго элемента. Итак, что я делаю, когда я получаю onActivityPaused(), не изменяю напрямую видимое значение false, вместо этого у вас есть таймер 3 секунды (это максимум, который должен быть запущен следующим действием), а если нет onActivityResumed ( ) в течение следующих 3 секунд, измените значение на false. Аналогично в onActivityResumed(), если есть таймер, я отменяю его. Подводя итог, видимый становится isAppInBackground.
Извините, не могу скопировать-вставить код...
Ответ 30
Еще одно простое и точное решение. Полный текст здесь
public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {
HashMap<String, Integer> activities;
BaseLifeCycleCallbacks() {
activities = new HashMap<String, Integer>();
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
//map Activity unique class name with 1 on foreground
activities.put(activity.getLocalClassName(), 1);
applicationStatus();
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
//map Activity unique class name with 0 on foreground
activities.put(activity.getLocalClassName(), 0);
applicationStatus();
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
/**
* Check if any activity is in the foreground
*/
private boolean isBackGround() {
for (String s : activities.keySet()) {
if (activities.get(s) == 1) {
return false;
}
}
return true;
}
/**
* Log application status.
*/
private void applicationStatus() {
Log.d("ApplicationStatus", "Is application background" + isBackGround());
if (isBackGround()) {
//Do something if the application is in background
}
}