如何判断Android应用程序是否在前台运行?

And*_*mas 81 android android-activity

我在我的Android应用程序中执行状态栏通知,由c2dm触发.如果应用程序正在运行,我不想显示通知.您如何确定应用程序是否正在运行且位于前台?

Gad*_*kan 111

或者,您可以检查方法ActivityManager运行的任务getRunningTasks.然后检查返回的任务列表中的第一个任务(前台任务),如果这是您的任务.
这是代码示例:

public Notification buildNotification(String arg0, Map<String, String> arg1) {

    ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> services = activityManager
            .getRunningTasks(Integer.MAX_VALUE);
    boolean isActivityFound = false;

    if (services.get(0).topActivity.getPackageName().toString()
            .equalsIgnoreCase(appContext.getPackageName().toString())) {
        isActivityFound = true;
    }

    if (isActivityFound) {
        return null;
    } else {
        // write your code to build a notification.
        // return the notification you built here
    }

}
Run Code Online (Sandbox Code Playgroud)

并且不要忘记GET_TASKSmanifest.xml文件中添加权限,以便能够getRunningTasks()在上面的代码中运行方法:

<uses-permission android:name="android.permission.GET_TASKS" />
Run Code Online (Sandbox Code Playgroud)

p/s:如果同意这种方式,请注意,此权限现已弃用.

  • 如果你想使用这段代码,别忘了添加<uses-permission android:name ="android.permission.GET_TASKS"/> (24认同)
  • 注意:此方法仅用于调试和呈现任务管理用户界面.这绝不应该用于应用程序中的核心逻辑,例如根据此处的信息在不同的行为之间进行决策.不支持此类用途,并且将来可能会破坏.例如,如果多个应用程序可以同时主动运行,则出于控制流程的目的而对此处的数据含义进行的假设将是不正确的. (14认同)
  • Nitpicks:在`getPackageName()`返回的String上调用`toString()`是多余的.另外,由于我们只对`getRunningTasks()`返回的第一个任务感兴趣,我们可以传递`1`而不是`Integer.MAX_VALUE`. (13认同)
  • 不幸的是,自Android L(API 20)以来,getRunningTasks()已被弃用.从L开始,此方法不再适用于第三方应用程序:引入以文档为中心的最新版本意味着它可以将人员信息泄露给调用者.为了向后兼容,它仍将返回其数据的一小部分:至少是调用者自己的任务,以及可能已知不敏感的其他一些任务,如home. (5认同)
  • 大概如果它只显示调用者的任务,那么第一个任务和顶级活动将永远是你的,这意味着这将永远返回真正的棒棒糖后. (2认同)
  • `activityManager .getRunningTasks`已从Lollipop折旧,不应用于任何应用程序构建逻辑.由谷歌本身推荐.那么现在应该使用什么? (2认同)

Wro*_*lai 52

作出这样一个全局变量private boolean mIsInForegroundMode;和分配false的价值onPause()true价值onResume().

示例代码:

private boolean mIsInForegroundMode;

@Override
protected void onPause() {
    super.onPause();
    mIsInForegroundMode = false;
}

@Override
protected void onResume() {
    super.onResume();
    mIsInForegroundMode = true;
}

// Some function.
public boolean isInForeground() {
    return mIsInForegroundMode;
}
Run Code Online (Sandbox Code Playgroud)

  • @Shelly但是,在同一个应用程序中切换活动时,您的变量会变为True/False/True.这意味着你必须有一个滞后来真正检测你的应用程序何时失去前景. (19认同)
  • 这不是最好的解决方案.查看下面的@Gadenkan解决方案. (10认同)
  • 但是这段代码只适用于某项活动,不是吗? (8认同)
  • @MurVotema:是的,确实如此.但是,只要发生变化,我们就可以自由地传递这个变量,例如传递给首选项或数据库. (2认同)

小智 46

这是一个非常古老的帖子,但仍然非常相关.以上接受的解决方案可能有效,但是错误.正如Dianne Hackborn所写:

这些API不适用于基于UI流程的应用程序,而是用于向用户显示正在运行的应用程序或任务管理器等.

是的,内存中有一个列表用于这些事情.但是,它是在另一个进程中关闭,由与您分开运行的线程管理,而不是您可以指望的事情(a)及时看到做出正确的决定,或者(b)在您返回时保持一致的图像.此外,关于"下一个"活动的内容的决定总是在切换发生的时刻完成,直到确切的点(活动状态被短暂锁定以进行切换),我们才实际上知道接下来会发生什么.

此处的实施和全球行为不能保证在未来保持不变.

正确的解决方案是实现:ActivityLifeCycleCallbacks.

这基本上需要一个Application Class,并且可以在那里设置处理程序以识别应用程序中活动的状态.

  • 以下是如何使用它的示例http://baroqueworksdev.blogspot.com/2012/12/how-to-use-activitylifecyclecallbacks.html (7认同)
  • 我认为这是最好的解决方案,未来可能不会破产.不知道为什么它得不到足够的票数. (2认同)
  • 如果你写一个示例代码,你会得到更多的选票,因为有些人没有例子跳过答案......但这是最好的解决方案...... (2认同)

hta*_*oya 23

正如Vinay所说,可能最好的解决方案(支持更新的Android版本,14 +)是ActivityLifecycleCallbacksApplication类实现中使用.

package com.telcel.contenedor.appdelegate;

import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

/** Determines global app lifecycle states. 
 * 
 * The following is the reference of activities states:
 * 
 * The <b>visible</b> lifetime of an activity happens between a call to onStart()
 * until a corresponding call to onStop(). During this time the user can see the
 * activity on-screen, though it may not be in the foreground and interacting with 
 * the user. The onStart() and onStop() methods can be called multiple times, as 
 * the activity becomes visible and hidden to the user.
 * 
 * The <b>foreground</b> lifetime of an activity happens between a call to onResume()
 * until a corresponding call to onPause(). During this time the activity is in front
 * of all other activities and interacting with the user. An activity can frequently
 * go between the resumed and paused states -- for example when the device goes to
 * sleep, when an activity result is delivered, when a new intent is delivered -- 
 * so the code in these methods should be fairly lightweight. 
 * 
 * */
public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks {

    /** Manages the state of opened vs closed activities, should be 0 or 1. 
     * It will be 2 if this value is checked between activity B onStart() and
     * activity A onStop().
     * It could be greater if the top activities are not fullscreen or have
     * transparent backgrounds.
     */
    private static int visibleActivityCount = 0;

    /** Manages the state of opened vs closed activities, should be 0 or 1
     * because only one can be in foreground at a time. It will be 2 if this 
     * value is checked between activity B onResume() and activity A onPause().
     */
    private static int foregroundActivityCount = 0;

    /** Returns true if app has foreground */
    public static boolean isAppInForeground(){
        return foregroundActivityCount > 0;
    }

    /** Returns true if any activity of app is visible (or device is sleep when
     * an activity was visible) */
    public static boolean isAppVisible(){
        return visibleActivityCount > 0;
    }

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

    public void onActivityDestroyed(Activity activity) {
    }

    public void onActivityResumed(Activity activity) {
        foregroundActivityCount ++;
    }

    public void onActivityPaused(Activity activity) {
        foregroundActivityCount --;
    }


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

    public void onActivityStarted(Activity activity) {
        visibleActivityCount ++;
    }

    public void onActivityStopped(Activity activity) {
        visibleActivityCount --;
    }
}
Run Code Online (Sandbox Code Playgroud)

在应用onCreate()方法中:

registerActivityLifecycleCallbacks(new ApplicationLifecycleManager());
Run Code Online (Sandbox Code Playgroud)

然后ApplicationLifecycleManager.isAppVisible()ApplicationLifecycleManager.isAppInForeground()将用于了解所需的状态.


Juo*_*nis 18

从API 16开始,您可以这样做:

static boolean shouldShowNotification(Context context) {
    RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(myProcess);
    if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
        return true;

    KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
    // app is in foreground, but if screen is locked show notification anyway
    return km.inKeyguardRestrictedInputMode();
}
Run Code Online (Sandbox Code Playgroud)


小智 15

仅供参考,如果您使用Gadenkan解决方案(这很棒!!)请不要忘记添加

<uses-permission android:name="android.permission.GET_TASKS" />
Run Code Online (Sandbox Code Playgroud)

清单.

  • 在android Lollipop中,不允许使用此权限 (9认同)

Jon*_*nik 14

稍微清理了Gadenkan解决方案的版本.把它放在任何Activity上,或者也许是你所有活动的基类.

protected boolean isRunningInForeground() {
    ActivityManager manager = 
         (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
    if (tasks.isEmpty()) {
        return false;
    }
    String topActivityName = tasks.get(0).topActivity.getPackageName();
    return topActivityName.equalsIgnoreCase(getPackageName());
}
Run Code Online (Sandbox Code Playgroud)

为了能够打电话getRunningTasks(),您需要在以下内容中添加AndroidManifest.xml:

<uses-permission android:name="android.permission.GET_TASKS"/>
Run Code Online (Sandbox Code Playgroud)

请注意ActivityManager.getRunningTasks() Javadoc所说的内容:

注意:此方法仅用于调试和呈现任务管理用户界面.这绝不应该用于应用程序中的核心逻辑,例如根据此处的信息在不同的行为之间进行决策.不支持此类用途,并且将来可能会破坏.

更新(2015年2月)

请注意,在API级别21getRunningTasks()弃用!

截至目前LOLLIPOP,第三方应用程序不再可以使用此方法:引入以文档为中心的最新文件意味着它可以将人员信息泄露给调用者.为了向后兼容,它仍将返回其数据的一小部分:至少是调用者自己的任务,以及可能已知不敏感的其他一些任务,如home.

所以我之前写的更为相关:

在许多情况下,您可能会想出更好的解决方案.例如,在做什么onPause()onResume(),也许在您的所有活动一BaseActivity.

(在我们的例子中,如果我们不在前台,我们不希望启动离线警报活动,所以在BaseActivity中onPause()我们只是取消订阅RxJava,Subscription听取"离线"信号.)


Cro*_*ack 9

跟进Gadenkan的回复我需要这样的东西,所以我可以判断我的应用程序是不是在前台运行,但我需要一些应用程序范围内的东西,并且不要求我在整个应用程序中设置/取消设置标记.

Gadenkan的代码几乎击中了头部,但它不是我自己的风格,并觉得它可能更整洁,所以在我的应用程序中它浓缩到这个.

if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()))
{
// App is not in the foreground
}
Run Code Online (Sandbox Code Playgroud)

(旁注:你可以删除!如果你想让支票反过来工作)

虽然采用这种方法,但您需要获得GET_TASKS许可.


Kei*_*ati 7

从支持库版本 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
}
Run Code Online (Sandbox Code Playgroud)

,现在您可以ProcessLifecycleOwner在任何想要检查应用程序状态的时候进行查询,例如检查应用程序是否在前台运行,您只需执行以下操作:

 boolean isAppInForeground = ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
 if(!isAppInForeground)
    //Show Notification in status bar
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

75082 次

最近记录:

7 年 前