Подтвердить что ты не робот

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

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

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

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

the red is my activity which is in the background while the dialogue is in the foreground

РЕДАКТИРОВАТЬ: Я пытался просто не использовать finish(), но тогда моя активность может быть возвращена в стек приложений, которые я пытаюсь избежать.

4b9b3361

Ответ 1

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

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

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

Источник: fooobar.com/questions/26541/...

Ответ 2

Если вы используете 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
    ....
}

Ответ 3

UPD: обновлено до состояния Lifecycle.State.RESUMED. Спасибо @htafoya за это.

В 2019 году с помощью новой библиотеки поддержки 28+ или AndroidX вы можете просто использовать:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

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

Ответ 4

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

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

Activity lifecycle demo

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

Ответ 5

Activity :: hasWindowFocus() возвращает вам логическое значение, которое вам нужно.

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

Вот пример класса, чтобы проверить видимость ваших активистов, где бы вы ни находились.

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

Ответ 6

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

1) Обратные вызовы LifeCycle

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

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

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

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

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

Ответ 7

У меня есть проект на github app-foreground-background-listen

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

Ответ 8

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

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

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

Ответ 9

Думаю, у меня есть лучшее решение. Потому что вы можете построить просто 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()

Ответ 10

Это может быть достигнуто эффективным способом, используя 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;
}
}

в вышеприведенном классе существует переопределяющий метод onActivityResumed 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")
    }

Ответ 11

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

Ответ 12

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

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

Ответ 13

Если вы хотите узнать, видна ли какая-либо активность вашего приложения на экране, вы можете сделать что-то вроде этого:

public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();

@Override
public void onActivityResumed(Activity activity) {
    visibleActivities.add((Class<Activity>) activity.getClass());
}

@Override
public void onActivityStopped(Activity activity) {
     visibleActivities.remove(activity.getClass());
}

public boolean isAnyActivityVisible() {
    return !visibleActivities.isEmpty();
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityDestroyed(Activity activity) {}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}}

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

class App extends Application{
     @Override
     public void onCreate() {
         registerActivityLifecycleCallbacks(myAppActivityCallbacks);
     }
}

Затем вы можете использовать метод isAnyActivityVisible() вашего экземпляра MyAppActivityCallbacks везде!

Ответ 14

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

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

Ответ 15

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

    }
};

и в режиме остановки:

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

Ответ 16

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

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

ЗАМЕЧАНИЕ, что вы можете использовать константный или строковый ресурс для строки "широковещательный идентификатор".

Ответ 17

Если вы используете 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);

Ответ 18

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

isDestroyed()

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

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

Ответ 19

Вот решение, использующее класс Application.

public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {

private WeakReference<Context> foregroundActivity;


@Override
public void onActivityResumed(Activity activity) {
    foregroundActivity=new WeakReference<Context>(activity);
}

@Override
public void onActivityPaused(Activity activity) {
    String class_name_activity=activity.getClass().getCanonicalName();
    if (foregroundActivity != null && 
            foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
        foregroundActivity = null;
    }
}

//............................

public boolean isOnForeground(@NonNull Context activity_cntxt) {
    return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}

public boolean isOnForeground(@NonNull String activity_canonical_name) {
    if (foregroundActivity != null && foregroundActivity.get() != null) {
        return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
    }
    return false;
}
}

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

((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);

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

Ответ 20

Я не знаю, почему никто не говорил о sharedPreferences для Activity A, устанавливая SharedPreference как это (например, в onPause()):

SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("is_activity_paused_a", true);
editor.commit();

Я думаю, что это надежный способ отслеживать действия visibilty.

Ответ 21

Будет ли Activity.onWindowFocusChanged(boolean hasFocus) полезен здесь? Это, плюс флаг уровня класса, что-то вроде isFocused, который устанавливает onWindowFocusChanged, будет простым способом рассказать в любой момент вашей деятельности, если он сфокусирован или нет. Из чтения документов это похоже на то, что он правильно установит "ложь" в любой ситуации, когда действие не находится непосредственно в физическом "переднем плане", например, если отображается диалоговое окно или лоток уведомлений выведен.

Пример:

boolean isFocused;
@Override
void onWindowFocusChanged (boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    isFocused = hasFocus;
}

void someMethod() {
    if (isFocused) {
        // The activity is the foremost object on the screen
    } else {
        // The activity is obscured or otherwise not visible
    }
}

Ответ 22

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

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

getIntent()

вернет значение null.: Р =