检查Android应用程序是否在后台运行

376

所谓背景,指的是应用程序的所有活动当前对用户都不可见。


3
可能是重复的问题:如何确定我的活动是否在前台。 - Phrogz
12
我有点困惑……为什么安卓不能在应用程序类中简单地提供一个覆盖方法来处理这个问题呢?难道在平台层面上无法解决吗?@Override protected void onApplicationSentToBackground() { } - Chuck D
2
@ChuckD - 这是有道理的,这也是Android SDK有时候喜欢避免做的事情。 :/ - Mark
http://codingaffairs.blogspot.com/2016/05/check-if-your-android-app-is-in.html - Developine
2
iOS在这方面做得非常好,不确定为什么谷歌让这变得如此困难。这是一个非常明显的需求。 - Jerry Destremps
显示剩余5条评论
37个回答

399

有几种方法可以检测您的应用程序是否在后台运行,但只有一种是完全可靠的:

  1. 正确的解决方案(感谢DanCommonsWareNeTeInStEiN
    通过使用Activity.onPauseActivity.onResume方法自己跟踪应用程序的可见性。将“可见性”状态存储在其他类中。好的选择是您自己实现的ApplicationService(如果您想从服务中检查活动可见性,还有几个变种的解决方案)。
     
    示例
    实现自定义的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" >
    

    为项目中的每个Activity添加onPauseonResume(如果您想的话,可以为您的Activities创建一个共同的祖先,但是如果您的activity已经扩展自MapActivity/ListActivity等,则仍需要手动编写以下内容):

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

     
    更新
    ActivityLifecycleCallbacks 在 API level 14(Android 4.0)中添加。您可以使用它们来跟踪应用程序的活动是否当前对用户可见。有关详细信息,请参见下面的Cornstalks' answer

  2. 错误的方法
    我曾经建议以下解决方案:

    您可以使用 ActivityManager.getRunningAppProcesses() 来检测当前前台/后台应用程序,它返回一个RunningAppProcessInfo记录列表。要确定您的应用程序是否在前台,请检查RunningAppProcessInfo.importance字段是否等于RunningAppProcessInfo.IMPORTANCE_FOREGROUND,而RunningAppProcessInfo.processName 是否等于您的应用程序软件包名称。

    此外,如果您从您的应用程序UI线程调用 ActivityManager.getRunningAppProcesses(),它将为您的任务返回importance IMPORTANCE_FOREGROUND,无论它实际上是否在前台。在后台线程中调用它(例如通过AsyncTask),它将返回正确的结果。

    虽然这个解决方案可能有效(实际上大多数情况下都能正常运行),但我强烈建议不要使用它。以下是原因。正如Dianne Hackborn所写的:

    这些API不是为了让应用程序基于其UI流而存在,而是用于显示用户正在运行的应用程序、任务管理器或类似功能。

    是的,有一个在内存中保存这些内容的列表。但是,它在另一个进程中,由比您运行的线程管理,并且不是您可以依赖的东西(a)及时看到以做出正确的决定或(b)在您返回时具有一致的图片。加上决定“下一个”活动要去哪里总是在切换发生的地方做出的,直到那个确切的点(状态被简短地锁定以执行切换的地方)我们才真正知道下一步会发生什么。

    而且,这里的实现和全局行为不能保证在未来保持不变。

    我希望在我在SO上发布答案之前能读到这些内容,但希望现在还不算太晚承认我的错误。

  3. 另一个错误的解决方案
    Droid-Fu 库中提到的一个答案使用了 ActivityManager.getRunningTasksisApplicationBroughtToBackground 方法。看看Dianne上面的评论并且也不要使用那个方法。


4
如何判断你是否按下了主屏幕键或其他应用已获得焦点:1)实现“良好解决方案”。2)在“OnStop”中请求“isActivityVisible”。 - Brais Gabin
30
很不幸,你所谓的“正确”解决方案对我不起作用。考虑你在应用程序中循环进行活动。那么会发生这样的情况:你的“inForeground”标志会像这样变化:True,False(在第一个活动的onPause和第二个活动的onResume之间),然后再变为True,等等。因此,你需要某种滞后效应。 - Radu
16
如果您无法直接控制所有活动,则此解决方案将无法使用。例如,如果您有来自第三方sdk的Activity甚至启动ACTION_VIEW意图。 - user123321
79
安卓系统真是一坨烂泥。竟然没人想过有人可能想要持久化应用级别的数据?别闹了。 - user317033
11
看起来这个问题的真正答案是“您无法正确地检查它”。所谓的“正确”解决方案最多只是一个替代方法,使用ActivityLifecycleCallbacks也是如此。您仍然需要考虑在活动之间进行切换,这将被注册为“未在前台”。让我感到困惑的是,您不能检查这样一个简单的事情... - serine
显示剩余20条评论

322

谷歌解决方案 - 不像以前的解决方案那样是黑客行为。使用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


14
这肯定是正确答案!它运行得很顺利 :D - JaviOverflow
7
哇,这比我的旧答案好多了。我给你点个赞。我更新了我的答案,引导人们去参考你的答案。 - Cornstalks
5
虽然这是一个正确的答案,但并不需要实现回调函数,您可以随时查询ProcessLifecycleOwner。请参考https://dev59.com/KHA65IYBdhLWcg3wuhIR#52678290。 - Keivan Esbati
7
如文档所述,“LifecycleOwner 适用于整个应用程序进程。请注意,如果您的应用程序有多个进程,则该提供程序不知道其他进程。”,因此这对于“多进程”应用程序无效,是否有一些 API 可以优雅地解决? - Kevin
4
@OnLifecycleEvent 注解已过时。建议使用 DefaultLifecycleObserver 或 LifecycleEventObserver 替代。来源:https://developer.android.com/reference/androidx/lifecycle/OnLifecycleEvent - Luciano Brum
显示剩余14条评论

268

请勿使用此答案

user1269737的答案是正确的(Google / Android批准的)方法,请阅读他们的答案并给予+1。

我将保留我的原始答案以供后人参考。这是2012年最好的可用方法,但现在Android已经为此提供了适当的支持。

原始答案

关键是使用ActivityLifecycleCallbacks(请注意,这需要Android API级别14(Android 4.0))。只需检查停止的活动数是否等于启动的活动数。如果它们相等,则您的应用正在后台运行。如果有更多的启动活动,则您的应用仍然可见。如果恢复的活动比暂停的活动多,则您的应用不仅可见,而且还在前台。因此,您的活动可以处于三种主要状态:可见且在前台,可见但不在前台以及不可见且不在前台(即在后台)。

这种方法的真正好处在于它没有异步问题getRunningTasks(),但您也不必修改应用程序中的每个Activity以在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's 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()的文档说:

请注意,在低内存情况下,系统没有足够的内存来保持您的活动进程在其 onPause() 方法被调用后运行时,可能永远不会调用此方法。

关键在于“保持您的活动进程运行...”如果达到了这种低内存情况,您的进程实际上已经被终止(不仅仅是您的活动)。这意味着检查后台状态的这种方法仍然有效,因为a)如果您的进程被杀死,无论如何都无法检查后台状态,b)如果您的进程重新启动(因为创建了新活动),则 MyLifecycleHandler 的成员变量(无论是静态还是非静态)将被重置为 0

这对配置更改有效吗?

默认情况下,不是。您必须在清单文件中显式设置configChanges = orientation | screensize(使用 | 和其他任何内容),并处理配置更改,否则您的活动将被销毁并重新创建。如果您不设置此项,则您的活动方法将按以下顺序调用: onCreate -> onStart -> onResume ->(现在旋转) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume 。正如您所看到的,没有重叠(通常,两个活动在切换时会非常短暂地重叠,这就是此后台检测方法的工作方式)。为了解决这个问题,您必须设置configChanges,以便您的活动不会被销毁。幸运的是,我已经在所有项目中设置了configChanges,因为屏幕旋转/调整大小时整个活动都被销毁是不可取的,因此我从未发现这是有问题的。(感谢dpimka让我记起来并纠正我!)

一个注释:

当我在这个答案中说“背景”时,我的意思是“您的应用程序不再可见”。 Android活动可以可见但不在前台(例如,如果有透明通知覆盖)。这就是为什么我更新了这个答案以反映这一点。

重要的是要知道,在切换活动时,Android有一个奇怪的中间状态,此时没有任何东西在前台。因此,如果您在活动之间(在同一个应用程序中)检查应用程序是否在前台,则会告诉您不在前台(即使您的应用程序仍然是活动的应用程序并且可见)。

ActivityonPause()方法中的super.onPause()之后,您可以检查您的应用是否在前台。请记住我刚刚谈到的奇怪的半途状态。
ActivityonStop()方法中的super.onStop()之后,您可以检查您的应用是否可见(即它不在后台)。

2
@Mewzer:我刚刚添加了一条你可能感兴趣的注释。具体来说,在super.onStop()之后的onStop()中检查后台运行,不要在onPause()中检查后台运行。 - Cornstalks
1
@Cornstalks,你对配置更改的理解是错误的 - 它们实际上会停止/恢复活动,除非在清单中设置了configChanges=orientation|screensize,这不是默认设置。但无论如何,感谢您的提示! - dimsuz
1
@Cornstalks 很好,谢谢!我已经在我的应用程序中使用了这种方法! - dimsuz
1
当我调用相机意图或从相册中选择图像时,恢复和停止的计数很匹配。我该如何知道用户按下主页按钮时应用程序是否已到达后台? - Software Sainath
1
@Cornstalks:如果应用程序包含一些半透明的活动,计数将会出错。从Android文档“暂停和恢复活动”中可以看到,“当一个半透明的活动遮挡了你的活动时,系统会调用onPause()方法并使活动处于暂停状态”,那么该如何处理呢? - Hanon
显示剩余16条评论

49

自支持库版本 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);

3
谢谢,这是最好、最简单的方法,在任何代码部分都适用,特别是在使用 FCM 时。 - Mihae Kheel
如果应用程序完全关闭,第一个方法会返回什么? - Evgeniy Mishustin
那么,有没有任何“IF”语句来查看应用程序是否在后台(前台)? - ekashking
@ekashking 只需将整个语句放在 if 语句中。例如: if(ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) => 应用程序在前台运行 - Keivan Esbati
1
处理生命周期 指向了一种不同的 声明 androidx.lifecycle 依赖项 的方式。此外,lifecycle-extensions 现在已被列为弃用。因此,在我的情况下,依赖关系看起来像这样:dependencies { def lifecycle_version = "2.2.0" implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" } - Nesho Neshev
显示剩余3条评论

28

自 Android API 16 开始,有一种简单的方法可以检查应用程序是否处于前台。它可能不是百分之百可靠的,但在Android上没有任何方法是完美无缺的。当您的服务从服务器接收更新并需要决定是否显示通知时,此方法足够好用了(因为如果 UI 处于前台,用户将会注意到更新而无需通知)。

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

这段代码应该放在Service类中还是其他类中,比如Application类?非常感谢。 - Woppi
只要你想在最后一行使用它作为布尔值进行检查,你可以将其放置在任何地方。 - AO_
这是AWS Android SDK推送通知所使用的相同方法。 - spakmad
然而,如果我按照https://dev59.com/32Qn5IYBdhLWcg3wrouL#38496939中提到的建议,在`AndroidManifest.xml`中的服务定义中添加[`android:process`](https://developer.android.com/guide/topics/manifest/service-element#proc),这个解决方案就不起作用了。 - Michael Osofsky
这是我在调试应用程序时唯一有效的方法,因为它可以启动应用程序(包括触发onStart/onResume),即使屏幕关闭也可以。这会导致在Android O中使用startService出现问题。 - Shenk
显示剩余2条评论

18

虽然check android application is in foreground or not?以及Determining the current foreground application from a background task or service中出现过Idolon的答案,但是该答案容易出错并且更加复杂。这里有一个更简单的方法:

在所有Activity都继承的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


3
“Idolon's answer is error prone” - 不幸的是,我同意你的看法。基于 Dianne Hackborn 在 Google Groups 中的评论,我已经更新了我的回答,请查看详细信息。 - Idolon
2
这也不是一个万无一失的解决方案。一个场景是,如果用户下拉通知面板,则既不会调用onPauseonStop,也不会调用onResume事件。那么如果没有触发这些事件,你该怎么办呢?! - user4750643
这让我想到了这个问题:http://stackoverflow.com/questions/33657102/method-unnecessarily-getting-called - Ruchir Baronia
遗憾的是,当屏幕关闭时启动活动时,此代码运行错误。在这种情况下,onResume和onPause被调用,使isVisible = false。 - CoolMind
如果屏幕关闭了,那不就意味着它不可见了吗?因此,从技术上讲,这种方法返回了正确的解决方案。我过去使用过这种方法,如果你实际上处于后台状态,弹出窗口出现,你下拉状态栏,屏幕关闭时启动,以及其他我尚未发现的情况,它将返回false。 - Jorge Aguilar
显示剩余4条评论

11

我尝试了使用Application.ActivityLifecycleCallbacks和其他许多建议的解决方案,但它们并没有按预期工作。感谢Sarge,我想出了一个相当简单和直接的解决方案,如下所述。

该解决方案的关键在于理解以下事实:如果我们有ActivityA和ActivityB,并且我们从ActivityA调用ActivityB(而不是调用ActivityA.finish),那么ActivityB的onStart()将在ActivityA的onStop()之前被调用。

这也是onStop()onPause()之间的主要区别,这些文章中没有提到。

所以基于这个Activity的生命周期行为,您可以简单地计算程序中onStart()onPause()分别被调用了多少次。请注意,对于您程序中的每个Activity,您必须重写onStart()onStop(),以便增加/减少用于计数的静态变量。以下是实现此逻辑的代码。请注意,我使用了一个扩展了Application的类,因此不要忘记在Manifest.xml中声明,即在Application标签中声明: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();
}

根据这个逻辑,有两种可能的情况:

  1. stateCounter = 0:停止的数量与启动的活动数量相等,这意味着应用程序正在后台运行。
  2. stateCounter > 0:启动的数量大于停止的数量,这意味着应用程序正在前台运行。

注意:stateCounter < 0 表示停止的活动数量多于启动的活动数量,这是不可能的。如果您遇到这种情况,则意味着您没有按照应该进行的增加/减少计数器。

现在你可以开始了。你应该在 onStop() 方法中检查你的应用程序是否处于后台运行状态。


我会将 if(Utilities.isApplicationOnBackground()) … 移到 Utilities 中。否则,只有特定的活动才能对此事件做出反应。 - Display Name

10

除非您自己跟踪,否则没有其他方法可以确定您的任何活动是否可见。也许您应该考虑提出一个新的StackOverflow问题,解释一下您尝试从用户体验中实现什么,这样我们就可以给您提供替代的实现思路。


2
在Android中,我们有一个名为“后台数据”的设置。当应用程序在后台运行时,此设置会关闭任何后台数据连接。我想为我的应用程序实现“后台数据”切换功能,这样当用户没有看到我的任何活动时,我希望我的服务停止进行任何数据传输,但是一旦我的任何活动恢复,我希望恢复数据传输。 - cppdev
1
@cppdev:希望“数据传输”是由一个“服务”进行的。如果是这样,请在活动出现和消失时通知服务。如果“服务”确定没有可见的活动,并且保持这种状态一段时间,那么在下一个逻辑停止点停止数据传输。是的,这将需要为每个活动编写代码,但就我所知,目前无法避免。 - CommonsWare
1
如果您想避免在所有活动之间复制粘贴公共代码,可以创建一个从Activity继承并实现生命周期方法的类MyActivityClass,并使所有活动都从MyActivityClass继承。但是,这对于PreferenceActivityMapActivity不起作用(请参见此问题)。 - Guillaume Brunerie
@CommonsWare 我已经尝试使用OnPause()和OnResume()来检查应用程序是否处于活动状态,但如果我的应用程序在后台运行而没有在视图屏幕中显示,如何检查它是否处于活动状态。 - Manoj
@CommonsWare 我已经尝试使用OnPause()和OnResume()来检查应用程序是否处于活动状态,但如果我的应用程序在后台运行而没有在视图屏幕中显示,如何检查它是否处于活动状态? - Manoj
@CommonsWare 我已经尝试使用OnPause()和OnResume()来检查应用程序是否处于活动状态,但如果我的应用程序在后台运行而没有在视图屏幕中显示,如何检查它是否处于活动状态? - Manoj

5
您可以使用ComponentCallbacks2来检测应用是否在后台运行。顺便提一下,这个回调仅在API Level 14(冰激凌三明治)及以上版本中才可用。
如果级别是ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN,则会调用以下方法: public abstract void onTrimMemory (int level) 此时应用处于后台状态。
您可以将此接口实现到activityservice等组件中。
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
     }
   }
}

1
尝试了您的答案,但不够可靠。当屏幕被锁定或按下“电源”按钮锁定屏幕时,onTrimMemory回调将不会被触发。如果您的应用程序可见并通过状态栏通知打开另一个应用程序,则它也不会始终返回TRIM_MEMORY_UI_HIDDEN。唯一可靠的解决方案是实现ActivityLifecycleCallbacks并根据自己的用例进行调整。 - velval

4

在@Cornstalks的回答基础上,增加了一些有用的功能。

额外的功能:

  • 引入单例模式,使您可以在应用程序中的任何地方执行以下操作:AppLifecycleHandler.isApplicationVisible() 和 AppLifecycleHandler.isApplicationInForeground()
  • 添加了处理重复事件的功能(请参见注释 // take some action on change of visibility 和 // take some action on change of in foreground)

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接