Как проверить активность на переднем плане или на видимом фоне?

У меня есть заставка на таймере. Моя проблема заключается в том, что до того, как я finish() свою деятельность, мне нужно проверить, что началось следующее действие, потому что всплывает диалоговое окно системы, и я хочу только finish() ; Как только пользователь выбрал вариант из диалогового окна?

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

Вот в чем проблема: красный – это моя деятельность, которая находится в фоновом режиме, а диалог находится на переднем плане:

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

EDIT: я пробовал просто не использовать finish() но тогда моя активность может быть возвращена в стек приложений, которые я пытаюсь избежать.

Solutions Collecting From Web of "Как проверить активность на переднем плане или на видимом фоне?"

Это то, что рекомендуется в качестве правильного решения:

Правильное решение (кредиты идут в Dan, CommonsWare и NeTeInStEiN). Следите за видимость вашего приложения самостоятельно, используя методы Activity.onPause, Activity.onResume. Сохранять статус «видимости» в каком-либо другом классе. Хороший выбор – это ваша собственная реализация Приложения или Услуги (есть также несколько вариантов этого решения, если вы хотите проверить активность активности в службе).

Пример Внедрение собственного класса приложения (обратите внимание на статический метод 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 к каждой деятельности в проекте (вы можете создать общего предка для своих действий, если хотите, но если ваша активность уже расширена из MapActivity / ListActivity и т. Д., Вам все равно нужно написать следующее вручную) :

 @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } 

В методе finish() вы хотите использовать isActivityVisible() чтобы проверить, видна ли активность или нет. Там вы также можете проверить, выбрал ли пользователь вариант или нет. Продолжайте, когда выполняются оба условия.

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

Источник: stackoverflow

Если вы используете API-интерфейс уровня 14 или выше, можно использовать android.app.Application.ActivityLifecycleCallbacks

 public class MyApplication extends Application implements ActivityLifecycleCallbacks { private static boolean isInterestingActivityVisible; @Override public void onCreate() { super.onCreate(); // Register to be notified of activity state changes registerActivityLifecycleCallbacks(this); .... } public boolean isInterestingActivityVisible() { return isInterestingActivityVisible; } @Override public void onActivityResumed(Activity activity) { if (activity instanceof MyInterestingActivity) { isInterestingActivityVisible = true; } } @Override public void onActivityStopped(Activity activity) { if (activity instanceof MyInterestingActivity) { isInterestingActivityVisible = false; } } // Other state change callback stubs .... } 

Это как раз разница между onPause и onStop событиями, описанными в документации класса Activity .

Если вы правильно поняли, что вы хотите сделать, выполните вызов finish() из вашей активности onStop чтобы завершить его. См. Прилагаемый образ демонстрационного приложения жизненного цикла активности . Вот как это выглядит, когда Activity B запускается из Activity A. Порядок событий происходит снизу вверх, поэтому вы можете видеть, что Activity A onStop вызывается после того, как Activity B onResume уже был вызван.

Демо-версия жизненного цикла

В случае, если отображается диалог, ваша активность затемняется в фоновом режиме и onPause только onPause .

Два возможных решения:

1) Обратные вызовы жизненного цикла

Используйте приложение, которое реализует ActivityLifecycleCallbacks и использует его для отслеживания событий жизненного цикла событий в вашем приложении. Обратите внимание, что ActivityLifecycleCallbacks для Android api> = 14. Для предыдущего Android api вам нужно реализовать его самостоятельно во всех ваших действиях 😉

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

2) Проверьте информацию о текущем процессе

Вы можете проверить состояние запущенного процесса с помощью этого класса RunningAppProcessInfo

Выполните список запущенных процессов с помощью ActivityManager.getRunningAppProcesses () и отфильтруйте список результатов, чтобы проверить требуемый файл RunningAppProcessInfo и проверить его «важность»,

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

Который использует очень простую логику и отлично работает со всеми уровнями API Android.

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

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

 private static boolean isInBackground; private static boolean isAwakeFromBackground; private static final int backgroundAllowance = 10000; public static void activityPaused() { isInBackground = true; final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { if (isInBackground) { isAwakeFromBackground = true; } } }, backgroundAllowance); Log.v("activity status", "activityPaused"); } public static void activityResumed() { isInBackground = false; if(isAwakeFromBackground){ // do something when awake from background Log.v("activity status", "isAwakeFromBackground"); } isAwakeFromBackground = false; Log.v("activity status", "activityResumed"); } 

В классе BaseActivity

 @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } 

Вы пытались не называть финиш, и помещали «андроид: noHistory =« true »в манифесте? Это предотвратит переход активности в стек.

Я должен сказать, что ваш рабочий процесс не является стандартным способом Android. В Android вам не нужно finish() свою активность, если вы хотите открыть другое действие из Intent. Что касается удобства пользователя, Android позволяет пользователю использовать «назад», чтобы вернуться к действию, которое вы открыли в своем приложении.

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

Думаю, у меня есть лучшее решение. Потому что вы можете просто создать MyApplication.activityResumed (); К каждой деятельности одним расширением.

Во-первых, вам нужно создать (например, CyberneticTwerkGuruOrc)

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

Затем создайте класс ActivityBase

 public class ActivityBase extends Activity { @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } } 

Наконец, когда вы создаете новую активность, вы можете просто расширять ее ActivityBase вместо Activity.

 public class Main extends ActivityBase { @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } } 

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

Если вы хотите проверить видимость своего приложения, вы можете просто позвонить

 MyApplication.isActivityVisible() 

Сохраните флаг, если вы приостановлены или возобновлены. Если вы возобновляете это означает, что вы находитесь на переднем плане

 boolean isResumed = false; @Override public void onPause() { super.onPause(); isResumed = false; } @Override public void onResume() { super.onResume(); isResumed = true; } private void finishIfForeground() { if (isResumed) { finish(); } } 

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

Например, если системный диалог запускается с помощью кнопки buttonclick, тогда прослушиватель onclick может быть похож на

 private OnClickListener btnClickListener = new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using")); checkFlag = true; //flag used to check } }; 

И в onstop деятельности:

 @Override protected void onStop() { if(checkFlag){ finish(); } super.onStop(); } 

Почему бы не использовать трансляции для этого? Вторая активность (та, которая должна быть поднята) может отправить локальную трансляцию следующим образом:

 //put this in onCreate(..) or any other lifecycle method that suits you best //notice the string sent to the intent, it will be used to register a receiver! Intent result = new Intent("broadcast identifier"); result.putString("some message");//this is optional LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result); 

Затем напишите простой приемник в пределах активности всплеска:

 //this goes on the class level (like a class/instance variable, not in a method) of your splash activity: private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //kill activity here!!! //mission accomplished! } }; 

И зарегистрируйте свой новый ресивер с помощью LocalBroadcastManager, чтобы прослушать трансляцию с вашего второго действия:

 //notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to! LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier")); 

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

Если вы используете finish() чтобы избежать запуска нового приложения в стеке (задаче) вашего приложения, вы можете использовать флаг Intent.FLAG_ACTIVITY_NEW_TASK при запуске нового приложения и вообще не называть finish() . Согласно документации , это флаг, который будет использоваться для реализации стиля стиля «пусковая установка».

 // just add this line before you start an activity intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); 

Это может быть эффективным путем использования Application.ActivityLifecycleCallbacks

Например, давайте возьмем имя класса Activity, поскольку ProfileActivity позволяет определить , находится ли он на переднем плане или в фоновом режиме

Сначала нам нужно создать наш класс приложения, расширив класс приложения

Который реализует

Application.ActivityLifecycleCallbacks

Позволяет быть моим классом Application следующим образом

Класс приложения

 public class AppController extends Application implements Application.ActivityLifecycleCallbacks { private boolean activityInForeground; @Override public void onCreate() { super.onCreate(); //register ActivityLifecycleCallbacks registerActivityLifecycleCallbacks(this); } public static boolean isActivityVisible() { return activityVisible; } public static void activityResumed() { activityVisible = true; } public static void activityPaused() { activityVisible = false; } private static boolean activityVisible; @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { //Here you can add all Activity class you need to check whether its on screen or not activityInForeground = activity instanceof ProfileActivity; } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } public boolean isActivityInForeground() { return activityInForeground; } } 

В вышеприведенном классе есть переопределяющий метод в ActiveAutivityResumed ActivityLifecycleCallbacks

  @Override public void onActivityResumed(Activity activity) { //Here you can add all Activity class you need to check whether its on screen or not activityInForeground = activity instanceof ProfileActivity; } 

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

Зарегистрируйте свой класс приложения в файле manifest.xml

 <application android:name=".AppController" /> 

Чтобы проверить активность погодных условий Переднего плана или фона в соответствии с приведенным выше решением, вызовите следующий метод в местах, которые необходимо проверить

 AppController applicationControl = (AppController) getApplicationContext(); if(applicationControl.isActivityInForeground()){ Log.d("TAG","Activity is in foreground") } else { Log.d("TAG","Activity is in background") } 

Используйте эти методы внутри Activity .

isDestroyed()

Добавлено в Api 17
Возвращает true, если окончательный вызов onDestroy () был выполнен в Activity, поэтому этот экземпляр теперь мертв.

isFinishing()

Добавлено в Api 1
Проверьте, работает ли эта активность в процессе отделки, либо потому, что вы вызвали ее (или), либо кто-то попросил ее закончить. Это часто используется в onPause (), чтобы определить, просто ли приостановлена ​​или полностью завершена операция.

Документация по утечкам памяти

Общая ошибка с AsyncTask заключается в том, чтобы зафиксировать значительную ссылку на Activity хоста (или Fragment ):

 class MyActivity extends Activity { private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() { // Don't do this! Inner classes implicitly keep a pointer to their // parent, which in this case is the Activity! } } 

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

Правильный способ сделать это – сделать вашу задачу static классом, который не фиксирует родителя и содержит слабую ссылку на главную Activity :

 class MyActivity extends Activity { static class MyTask extends AsyncTask<Void, Void, Void> { // Weak references will still allow the Activity to be garbage-collected private final WeakReference<MyActivity> weakActivity; MyTask(MyActivity myActivity) { this.weakActivity = new WeakReference<>(myActivity); } @Override public Void doInBackground(Void... params) { // do async stuff here } @Override public void onPostExecute(Void result) { // Re-acquire a strong reference to the activity, and verify // that it still exists and is active. MyActivity activity = weakActivity.get(); if (activity == null || activity.isFinishing() || activity.isDestroyed()) { // activity is no longer valid, don't do anything! return; } // The activity is still valid, do main-thread stuff here } } } 

Я обычно делал,

Если деятельность не находится на переднем плане

getIntent ()

Вернет null. : Р =