【问题标题】:check android application is in foreground or not? [duplicate]检查android应用程序是否在前台? [复制]
【发布时间】:2011-12-13 13:23:43
【问题描述】:

对于这个问题,我经历了很多答案。但这都是关于单个活动的。如何检查整个应用程序是否在前台运行?

【问题讨论】:

标签: android


【解决方案1】:

我不明白你想要什么,但你可以通过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 问题 Determining the current foreground application from a background task or service 了解更多信息..

谢谢..

【讨论】:

  • 我每次都收到来自服务器的通知..如果应用程序在前台运行,我不想在前台运行时显示该通知..
  • 你好兄弟......它现在没有得到......每次它返回真实值。怎么办?
  • 该解决方案有一个错误,因为如果应用程序有正在运行的服务,它的重要性可能是 RunningAppProcessInfo.IMPORTANCE_FOREGROUND。更完整的解决方案在这里:stackoverflow.com/questions/2166961/…
  • 这是我最初在Android: Is application running in background? 线程中提出的答案。然而事实证明它是不可靠的,而且ActivityManager 用于背景/前景检查的用法是discouraged by Android authors。您可以查看我的以下答案以了解详细信息:stackoverflow.com/a/5862048/648313
  • 这需要清单中的特殊权限“GET_TASKS”。向 IMO 询问太多了。
【解决方案2】:

2020 年 10 月更新:在此线程上查看基于生命周期扩展的解决方案。这种方法似乎奏效了,它更优雅、更现代。


到目前为止我发现的最简洁且不被弃用的方法如下:

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

因为如果屏幕锁定,则不会收到通知。我查看了框架,但其目的并不完全清楚。我会删除它。检查进程信息状态就足够了:-)

【讨论】:

  • 不幸的是,由于 ActivityManager.getMyMemoryState(),它只能用于 API > 15
  • Aps,对不起。我使用 Min SDK 16。
  • isAppOpened()是哪个类的方法?我无法在应用程序和活动中找到它。
  • 这是我自己的方法。它与解决方案无关,实际上:-)
  • 来吧伙计们,这还不错,2017 年 API 16+ 意味着 99%+
【解决方案3】:

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

要了解这种方法,请查看并排活动生命周期的答案:Activity side-by-side lifecycle

【讨论】:

  • 回答任何应用程序而不是用户应用程序的活动。
  • 是的.. 但请检查为什么不建议使用其他方法:stackoverflow.com/posts/5862048/revisions
  • 这确实可以查看活动是在前台还是后台
  • 它会检查您正在开发的应用程序的任何活动是在前台还是后台。不是一个具体的。但是很容易将其更改为知道哪个在前台。使用 Class 和 onResume setClass(currentActivity) onStop setClass(null); 代替布尔值
  • 如果活动被切换,这也会被调用!
【解决方案4】:

借助新的 Android 生命周期架构扩展,我们可以轻松实现这一目标。

只需确保在 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>

现在,每当应用程序进入前台或后台时,我们都会收到与声明的两个方法关联的日志。

【讨论】:

  • 这并不总是有效。需要先调用它以确定它是否在前台。例如,尝试在其 onCreate 函数上检查类 ArchLifecycleApp,如果它在前台。
  • 在 AndroidX 中,这个库现在被称为 androidx.lifecycle:lifecycle-extensions
  • 它运行良好,但应用程序进入后台似乎有很短的时间延迟。应用程序进入前台是及时的。
  • 我认为如果操作系统唤醒您的应用程序来处理推送通知,这会错误地将您的应用程序标记为前台?如果我错了,请纠正我。
【解决方案5】:

Android 架构组件库您可以使用ProcessLifecycleOwneronStartonStop 事件设置整个应用程序进程的侦听器。为此,请让您的应用程序类实现LifecycleObserver 接口,并将onStartonStop 的一些注释添加到您的前台和后台方法中。

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

}

【讨论】:

    【解决方案6】:

    我已尝试使用正在运行的进程中的包过滤器。但这很奇怪。取而代之的是,我尝试了新的解决方案,并且效果很好。我检查了很多次,通过这个模块得到了完美的结果。

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

    【讨论】:

    • 我认为这个答案很好,但是如果您想知道实际显示活动/视图的时间,最好将计数器放入 onActivityResumed/onActivityPaused 中。
    • 这就是我们需要在每个活动中加入的方式。以后会更复杂。所以这个很好
    【解决方案7】:

    检查应用是在后台还是前台。如果应用在后台,此方法将返回 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;
    }
    

    【讨论】:

    • 它打开我的应用程序天气我杀死了应用程序。
    • GET_TASKS 已弃用
    【解决方案8】:

    我通过创建一个基本活动类找到了一个简单的解决方案,你必须从这里扩展你的所有活动类:

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

    【讨论】:

    【解决方案9】:

    对此没有全局回调,但对于每个活动,它都是 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();
    
        }
    }
    
    
    }
    

    【讨论】:

      【解决方案10】:

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

      请告诉我它是否适合你们所有人。

      【讨论】:

        【解决方案11】:

        基于 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);
        

        【讨论】:

          【解决方案12】:

          在您的应用程序类中尝试 ActivityLifecycleCallbacks。

          【讨论】:

            【解决方案13】:

            以下是最新 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;
            

            希望对您有所帮助,谢谢。

            【讨论】:

            • 不适用于带有 Android 6.0.1 的 CT50
            • @Krzysztof Huminski,getTaskInfo() 和 getTaskInfo() 从 api 21 (Lollipop) 开始可用,而不是 api 23 (M)。
            【解决方案14】:

            以下解决方案适用于 API 级别 14+

            背景 ComponentCallbacks2 — 查看文档并不是 100% 清楚你将如何使用它。但是,仔细观察,您会注意到 onTrimMemory 方法传入了一个标志。这些标志通常与内存可用性有关,但我们关心的是 TRIM_MEMORY_UI_HIDDEN。通过检查 UI 是否隐藏,我们可以假设应用程序现在在后台。不是很明显,但它应该可以工作。

            前景化 ActivityLifecycleCallbacks — 我们可以通过覆盖 onActivityResumed 并跟踪当前应用程序状态(前景/背景)来使用它来检测前景。

            创建将由自定义应用程序类实现的接口

            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"
            

            【讨论】:

            • 似乎appInForeground 永远不会再变成假的了。
            【解决方案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) {
            
                }
            }
            

            【讨论】:

            • 为什么是计数器而不是简单的布尔值?/
            猜你喜欢
            • 1970-01-01
            • 2016-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-20
            • 2012-03-21
            • 1970-01-01
            相关资源
            最近更新 更多