Проверить приложение Android на переднем плане или нет?

Я рассмотрел множество ответов на этот вопрос. Но все это о единственной активности. Как проверить, работает ли все приложение на переднем плане или нет?

Ответ 1

Я не понимаю, что вы хотите, но вы можете обнаружить приложение foreground/background в настоящее время с вызовом ActivityManager.getRunningAppProcesses().

Что-то вроде,

class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {

  @Override
  protected Boolean doInBackground(Context... params) {
    final Context context = params[0].getApplicationContext();
    return isAppOnForeground(context);
  }

  private boolean isAppOnForeground(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    if (appProcesses == null) {
      return false;
    }
    final String packageName = context.getPackageName();
    for (RunningAppProcessInfo appProcess : appProcesses) {
      if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
        return true;
      }
    }
    return false;
  }
}

// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();

Также дайте мне знать, если я неправильно понимаю.

ОБНОВЛЕНИЕ: Посмотрите на этот вопрос SO Определение текущего приложения переднего плана из фоновой задачи или службы для получения дополнительной информации..

Спасибо..

Ответ 2

@user370305 ответ с ошибкой и обескуражен разработчиками ОС Android (проверьте https://groups.google.com/forum/#!msg/android-developers/zH-2bovZSLg/L2YM8Z1N-HwJ)

Существует гораздо более простой подход:

В BaseActivity все действия расширяются:

protected static boolean isVisible = false;

@Override
public void onResume() {
   super.onResume();
   setVisible(true);
}

@Override
public void onPause() {
    super.onPause();
    setVisible(false);
}

Всякий раз, когда вам нужно проверить, находится ли какая-либо из ваших приложений на переднем плане, просто проверьте isVisible();

Чтобы понять этот подход, проверьте этот ответ о жизненном цикле действий "бок о бок": Жизненный цикл активности бок о бок

Ответ 3

Самый простой и не устаревший способ, который я нашел до сих пор, сделать следующее:

@Override
public boolean foregrounded() {
    ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(appProcessInfo);
    return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
}

Он работает только с SDK 16 +.

ИЗМЕНИТЬ

Я удалил из этого кода следующий код:

KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();

поскольку он не получает уведомлений, если экран заблокирован. Я взглянул на рамки, и цель этого не совсем ясна. Я бы убрал его. Проверка состояния информации о состоянии будет достаточно: -)

Ответ 4

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

private int numRunningActivities = 0;

 public void onCreate() {
        super.onCreate();
this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

                @Override
                public void onActivityStarted(Activity activity) {
                    numRunningActivities++;
                    if (numRunningActivities == 1) {
                        LogUtils.d("APPLICATION", "APP IN FOREGROUND");
                    }

                }

                @Override
                public void onActivityStopped(Activity activity) {

                    numRunningActivities--;
                    if (numRunningActivities == 0) {
                       Log.e("", "App is in BACKGROUND") 
                    }
                }


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

                @Override
                public void onActivityResumed(Activity activity) {
                }

                @Override
                public void onActivityPaused(Activity activity) {
                }

                @Override
                public void onActivityDestroyed(Activity activity) {
                }

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

Ответ 5

проверьте, находится ли приложение в фоновом режиме или переднем плане. Этот метод вернет true, если приложение находится в фоновом режиме.

Сначала добавьте разрешение GET_TASKS на ваш AndroidManifest.xml

private boolean isAppIsInBackground(Context context) {
    boolean isInBackground = true;
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
        List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
            if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                for (String activeProcess : processInfo.pkgList) {
                    if (activeProcess.equals(context.getPackageName())) {
                        isInBackground = false;
                    }
                }
            }
        }
    } else {
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        if (componentInfo.getPackageName().equals(context.getPackageName())) {
            isInBackground = false;
        }
    }

    return isInBackground;
}

Ответ 6

Благодаря новой архитектуре Android Architecture Lifecycle мы можем достичь этого с максимальной легкостью.

Просто убедитесь, что вы тянете эту зависимость в файле build.gradle:

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.0"
}

Затем в вашем классе Application используйте следующее:

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        Log.d("MyApp", "App in background")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        Log.d("MyApp", "App in foreground")
    }
}

В конце обновите файл AndroidManifest.xml с помощью:

<application
    android:name=".ArchLifecycleApp"
    //Your extra code
    ....>
</application>

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

Ответ 7

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

public class BaseActivity extends ActionBarActivity {

@Override
protected void onResume() {
    ApplicationStateChecker.view_resumed(this);
    super.onResume();
}

@Override
protected void onStop() {
    ApplicationStateChecker.view_stopped(this);
    super.onStop();

}

@Override
protected void onPause() {
    ApplicationStateChecker.view_paused(this);
    super.onPause();

}

}

Класс ApplicationStateChecker:

public class ApplicationStateChecker {

private  static final String _pause_string = "paused";
private  static final String _resume_string = "resumed";

private static String _view_lastState;
private static boolean _from_background = true;

public static void view_paused(Activity activity){
    _view_lastState = _pause_string;
}

public static void view_stopped(Activity activity){

    if (  _view_lastState.equals(_pause_string) ){
        //if stop called and last event was pause then app is brought to background
        _from_background = true;
    }  //if

}

public static void view_resumed(Activity activity){

    if (  _from_background ) {
       //Do your stuff here , app is brought to foreground 

    }  //if

    _from_background = false;
    _view_lastState = _resume_string;
}

Ответ 8

Для этого нет глобального обратного вызова, но для каждого действия это onStop(). Вам не нужно возиться с атомом int. Просто введите глобальный int с количеством запущенных действий, в каждом действии добавьте его в onStart() и уменьшите его на onStop().

public class BaseActivity extends ActionBarActivity {
public static int count = 0;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}


@Override
protected void onStart() {
    super.onStart();
    count = count + 1;
    Log.d(TAG, "onStart" + count);
    if (count == 1) {

       Toast.makeText(getApplicationContext(), "online", Toast.LENGTH_SHORT).show();

    }

}



protected void onStop() {
    super.onStop();
    count = count - 1;
    if (count == 0) {

        Toast.makeText(getApplicationContext(), "offline", Toast.LENGTH_SHORT).show();

    }
}


}

Ответ 9

Ответы cesards верны, но только для API > 15. Для более низких версий API я решил использовать метод getRunningTasks():

   private boolean isAppInForeground(Context context)
    {
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
        {
            ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
            ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
            String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();

            return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
        }
        else
        {
            ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
            {
                return true;
            }

            KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
            // App is foreground, but screen is locked, so show notification
            return km.inKeyguardRestrictedInputMode();
        }
    }

Пожалуйста, дайте мне знать, если он работает для вас всех.

Ответ 10

Попробуйте ActivityLifecycleCallbacks в вашем классе Application.

Ответ 11

Ниже приведено обновленное решение для последней версии Android SDK.

String PackageName = context.getPackageName();
        ActivityManager manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        ComponentName componentInfo;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            List<ActivityManager.AppTask> tasks = manager.getAppTasks();
            componentInfo = tasks.get(0).getTaskInfo().topActivity;
        }
        else
        {
            List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
            componentInfo = tasks.get(0).topActivity;
        }

        if (componentInfo.getPackageName().equals(PackageName))
            return true;
        return false;

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

Ответ 12

Ни одна из решений, основанная на getRunningTasks(), не работает в последних версиях Android, getRunningTasks() устарел на уровне API 21. Даже если он все еще используется, он делает не возвращать достаточную информацию, чтобы определить, находится ли приложение на переднем плане.

Вместо этого расширьте класс Application и используйте Application.ActivityLifecycleCallbacks для отслеживания состояния видимости приложения.

public class MyApplication extends Application {
    static final String APP_STATE_FOREGROUND = "com.xxx.appstate.FOREGROUND";
    static final String APP_STATE_BACKGROUND = "com.xxx.appstate.BACKGROUND";
    private static int m_foreground = -1;
    private Handler m_handler = new Handler();
    private Runnable m_guard;

    public static boolean isForeground() {
        return m_foreground == 1;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {

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

            @Override
            public void onActivityStarted(Activity activity) {
            }

            @Override
            public void onActivityResumed(Activity activity) {
                if(m_guard != null) {
                    m_handler.removeCallbacks(m_guard);
                    m_guard = null;
                }
                if(m_foreground == 1)
                    return;
                m_foreground = 1;
                sendBroadcast(new Intent(APP_STATE_FOREGROUND));
            }

            @Override
            public void onActivityPaused(Activity activity) {
                if(m_foreground == 0)
                    return;
                /*
                 * Use a 400ms guard to protect against jitter
                 * when switching between two activities
                 * in the same app
                 */
                m_guard = new Runnable() {
                    @Override
                    public void run() {
                        if(m_foreground == 1) {
                            m_foreground = 0;
                            sendBroadcast(new Intent(APP_STATE_BACKGROUND));
                        }
                    }
                };
                m_handler.postDelayed(m_guard, 400);
            }

            @Override
            public void onActivityStopped(Activity activity) {
            }

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

            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });
    }
}

Использование таймера защиты 400 мс устраняет ложное обнаружение состояния фона при переключении между действиями в одном приложении. Состояние фона/переднего плана можно запросить в любое время, используя:

MyApplication.isForeground();

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

private static IntentFilter m_appStateFilter;

static {
    m_appStateFilter = new IntentFilter();
    m_appStateFilter.addAction(MyApplication.APP_STATE_FOREGROUND);
    m_appStateFilter.addAction(MyApplication.APP_STATE_BACKGROUND);
}

private BroadcastReceiver m_appStateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(MyApplication.APP_STATE_FOREGROUND)) {
            /* application entered foreground */
        } else if (action.equals(MyApplication.APP_STATE_BACKGROUND)) {
            /* application entered background */
        }
    }
};
registerReceiver(m_appStateReceiver, m_appStateFilter);

Ответ 13

Ниже решения работает с уровня API 14+

Фоновое представление ComponentCallbacks2. Рассмотрение документации не на 100% ясно, как вы это используете. Однако присмотритесь внимательно, и вы заметите, что метод onTrimMemory проходит под флагом. Эти флаги, как правило, относятся к доступности памяти, но тот, который нам интересен, - TRIM_MEMORY_UI_HIDDEN. Проверяя, скрыт ли пользовательский интерфейс, мы можем предположить, что приложение теперь находится в фоновом режиме. Не совсем очевидно, но он должен работать.

Foregrounding ActivityLifecycleCallbacks - мы можем использовать это для обнаружения переднего плана, переопределяя onActivityResumed и отслеживая текущее состояние приложения (Foreground/Background).

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

interface LifecycleDelegate {
    fun onAppBackgrounded()
    fun onAppForegrounded()
}

Создайте класс, который будет реализовывать ActivityLifecycleCallbacks и ComponentCallbacks2 и переопределяет методы onActivityResumed и onTrimMemory

// Take an instance of our lifecycleHandler as a constructor parameter
class AppLifecycleHandler(private val lifecycleDelegate: LifecycleDelegate) 
: Application.ActivityLifecycleCallbacks, ComponentCallbacks2 // <-- Implement these 
  {
private var appInForeground = false

      // Override from Application.ActivityLifecycleCallbacks
    override fun onActivityResumed(p0: Activity?) {
       if (!appInForeground) {
          appInForeground = true
          lifecycleDelegate.onAppForegrounded()
       }
    }

      // Override from ComponentCallbacks2
    override fun onTrimMemory(level: Int) { 
       if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
       // lifecycleDelegate instance was passed in on the constructor
          lifecycleDelegate.onAppBackgrounded()
       }
    }
}

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

class App : Application(), LifeCycleDelegate {

    override fun onCreate() {
        super.onCreate()
        val lifeCycleHandler = AppLifecycleHandler(this)
        registerLifecycleHandler(lifeCycleHandler)
    }

    override fun onAppBackgrounded() {
        Log.d("Awww", "App in background")
    }

    override fun onAppForegrounded() {
        Log.d("Yeeey", "App in foreground")
    }

    private fun registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) {
        registerActivityLifecycleCallbacks(lifeCycleHandler)
        registerComponentCallbacks(lifeCycleHandler)
    }

}

В Manifest установите CustomApplicationClass

<application
        android:name=".App"

Ответ 14

Библиотека компонентов Android Architecture вы можете использовать ProcessLifecycleOwner для настройки слушателя на весь процесс приложения для событий onStart и onStop. Чтобы сделать это, сделайте свой класс приложения реализованным интерфейсом LifecycleObserver и добавьте некоторые аннотации для onStop и onStart к вашим основным и фоновым методам.

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        Log.d("Awww", "App in background")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        Log.d("Yeeey", "App in foreground")
    }

}

Ответ 15

С Android 19 вы можете зарегистрировать обратный вызов жизненного цикла приложения в своем классе Application onCreate() следующим образом:

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new AppLifecycleCallback());
}

AppLifecycleCallback выглядит так:

class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
    private int numStarted = 0;

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

    }

    @Override
    public void onActivityStarted(Activity activity) {
        if (numStarted == 0) {
           //app went to foreground
        }
        numStarted++;
    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        numStarted--;
        if (numStarted == 0) {
            // app went to background
        }
    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}