确定前台应用程序是否被禁止?

3
有很多原因需要检测应用是否在前台。例如,作为触发GCM/C2DM推送通知的条件,许多应用程序都有充分的理由在前台和后台实现不同的行为。另一个原因可能是关闭消耗宝贵资源的服务,例如在后台任务中查询服务器。
要明确一点:我所看到的背景应用程序的定义是:没有任何活动调用onStart()方法,并且尚未调用onStop()方法。那是因为活动只在其生命周期中对用户可见。
从另一方面来说 -
  • 似乎Google不希望应用程序对主页按钮做出反应(它不是API的一部分)

  • 将对“根/主”活动上的onBackPressed()做出反应作为离开Activity的指示器肯定不是好主意(因为许多用户使用主页按钮而不是返回按钮)

  • API中没有允许确定应用程序是否在前台(根据我的定义...)的方法

如果我没有错过API中的任何内容,并且确实是这种情况 - 为什么没有办法轻松确定应用程序是否在前台???!!! 我知道可以做什么来确定应用程序是否在前台,如本帖中所述 - 如何检测Android应用程序何时进入后台并返回前台
但是正如@Emil所说 - 这需要特殊权限,或需要一些棘手的逻辑,这很快就会变得难以维护,并且它闻起来像是一个糟糕的方法(尽管这是我现在正在做的事情,因为我没有更好的想法...)
我的问题基本上是:
  • 是否没有这样的API方法是有原因的?

  • 考虑应用程序是否在前台不是一个好方法吗?

  • 是否有其他方法可以知道应用程序是否在前台?

4个回答

5
考虑应用程序是否在前台或后台是一种不好的方法吗?
根据前后台来进行考虑是合理的。
还有其他方法可以知道应用程序是否在前台吗?
您可以将此划分为两组场景:
1.当前台/后台状态发生变化时立即采取操作的情况。 2.某些其他事件发生(AlarmManager警报、系统广播等),此时您希望根据您是否处于前台来采取不同的操作。
对于前一种情况,onUserLeaveHint()是最可靠的简单选项。我不能保证它能够覆盖所有情况,但例如它应该处理HOME场景。您也可以在静态数据成员中维护已启动活动的引用计数,并尝试使用它。
对于后一种情况,有序广播可能很有用。

你的回答真的让我头脑清晰了...我没有想到有序广播可以作为第二种情况的解决方案。它似乎非常适合那种情况。至于第一种情况-我不熟悉onUserLeaveHint()方法。知道它的存在很好,但正如你所说-它仍然不能涵盖所有情况..静态变量表示已启动但未停止的活动数量是我正在做的事情,我想在听取你的建议后,我会接受这个解决方案,而不觉得它是一个糟糕的解决方案.. :) - Tal Kanel

1
使用新的Android架构组件,可以轻松地知道您的应用程序是在前台还是后台运行。
就像活动范围生命周期所有者一样,有一个通用进程生命周期所有者,您可以订阅并获取生命周期更新。
例如:
添加以下代码以注册为生命周期观察者
ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleListener)

为了接收相关回调,需要使用以下代码。
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onApplicationOnStartEvent() {

}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onApplicationOnStopEvent() {

}

不要忘记在不需要观察者时将其移除

ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleListener);

更多信息和示例可以在这篇优秀的文章中找到:

https://proandroiddev.com/detecting-when-an-android-app-backgrounds-in-2018-4b5a94977d5c


0

我也遇到了同样的问题。我想在我的活动不在前台模式时显示推送通知。请查看以下代码,你会得到答案。

    Context ctx = context.getApplicationContext();

    ActivityManager am = (ActivityManager) context
            .getSystemService(ACTIVITY_SERVICE);

    // get the info from the currently running task
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);

    PackageManager pm = this.getPackageManager();

    try {
        /**
         * take fore ground activity name
         */
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        if (printLog == true) {
            Log.d("Home", "CURRENT Activity ::"
                    + taskInfo.get(0).topActivity.getClassName());
            Log.d("Home", "Number Of Activities : "
                    + taskInfo.get(0).numRunning);
            Log.d("Home",
                    "Componenet Info : " + componentInfo.getPackageName());
            Log.d("Home",
                    "Componenet Info : " + componentInfo.getClassName());
        }
        /**
         * All activities name of a package to compare with fore ground
         * activity. if match found, no notification displayed.
         */
        PackageInfo info = pm.getPackageInfo(
                "<PackageName>",
                PackageManager.GET_ACTIVITIES);
        ActivityInfo[] list = info.activities;

        for (int i = 0; i < list.length; i++) {
              Log.d("TAG","Activity : "+list[i].name);
        }

    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }

要使用此功能,您必须在您的清单文件中获得许可。

uses-permission android:name="android.permission.GET_TASKS"

如果我无法理解您的问题,请原谅。


谢谢您的回答,但我附上了另一篇帖子的链接,显示我已经知道这个答案。您可以在问题正文中看到它。 - Tal Kanel

0
如果您需要从在后台运行的服务中了解应用程序是否在后台或前台(否则没有意义),那么您可以使用绑定(binding),也就是在所有活动的 onResume 中绑定,而在所有活动的 onPause 中解除绑定。这样,在您的服务中,您不仅可以管理您的应用程序对用户的可见性,还可以管理任何时候打开的活动。与静态变量相比,它也是不泄漏的、更稳定的(如果必要,可以进行清理),因为您使用的是 Android 的 API,并依赖于 Android 操作系统代码本身的正确性。

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