检查应用是否在后台运行

6

我实际上正在使用这段代码来检查应用程序是否在onPause时进入后台。

public static boolean isApplicationSentToBackground(final Context context) {
    ActivityManager am = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE );
    List<RunningTaskInfo> tasks = am.getRunningTasks( 1 );
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get( 0 ).topActivity;
        String name = LockScreenActivity.class.getName();
        String topAPN = topActivity.getPackageName();
        String conAPN = context.getPackageName();

        if (topActivity.getClassName().equals( name ) || !topActivity.getPackageName().equals( context.getPackageName() )) {
            return true;
        }
    }
    return false;
}

此代码在Android 4.4版本中一直运行得很好。但现在,如果我检查topAPNconAPN,它们会相等(而且当应用在Android <= 4.3的后台运行时,它们始终不相等)。
你知道如何解决这个问题吗?是否有什么变化?

注意:您的活动将在第一次启动活动时调用onResume,因此您可能希望在onPause中设置一个布尔值来向您的应用程序发出信号,表明它实际上已经进入了后台。我相信在后台与不可见是相同的。 - Noman Arain
我知道@NomanArain,我已经看到了那篇帖子,我知道我的方法不是正确(或安全)的检查方式,但在onPause中,您不知道您的应用程序是否真正处于后台状态,您只知道如果您的Activity(其中调用了onPause)不再对用户可见。这并不意味着您的应用程序此时在后台运行,直到您获得或未获得onResume。最好的解决方案(目前不存在)将是如果Android为您的应用程序提供精确的事件,通知您是否在后台或前台。 - StErMi
这个怎么样?https://dev59.com/KHA65IYBdhLWcg3wuhIR#13809991 - Noman Arain
那可能是一个可行的解决方案,但你必须在清单文件中禁用配置更改,否则你会遇到与 onPause 被转移到 onDestroy 相同的问题(onDestroy 并不意味着你的应用程序在后台运行。onDestroy 也可能会在配置更改时被调用)。从清单文件中禁用配置是一个不好的选择,因为你需要自己手动处理它。 - StErMi
它不起作用的原因是因为它完全不可靠:阅读文档:注意:此方法仅用于调试和呈现任务管理用户界面。这永远不应该用于应用程序中的核心逻辑,例如根据此处找到的信息决定不同行为之间的区别。这样的用法不受支持,并且很可能会在未来出现故障。 - Martin Marconcini
显示剩余6条评论
2个回答

5

我面临相同的问题,但我已经解决了这个问题,只需使用这段代码即可。

public static boolean isApplicationSentToBackground(final Context context) {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }
    return false;
}

在onPause方法中,这样调用该函数:
 @Override
protected void onPause() {
    super.onPause();
    handler.sendMessage(new Message());
}

Handler handler=new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        if (DeviceManager.isApplicationSentToBackground(getApplicationContext())) {
          paused = true;
      }
        return false;
    }
});

我不确定具体原因,但可能是由于处理程序中的不同线程导致我获得了正确的值。

1
你应该注意,在handleMessage重写方法中,你的paused布尔值应该是静态的。否则,将应用程序置于后台并返回会导致该布尔值重置。 - portfoliobuilder
@portfoliobuilder 是的,它必须是静态的。 - sheetal

0

这段代码适用于Android 4.4,我已经在onStop中声明并使用了这个方法,代码如下:

// 应用程序的代码放在后台

@Override
protected void onStop() {
super.onStop();

    if (AppConstants.isAppSentToBackground(getApplicationContext())) {
        // Do what ever you want after app close simply Close session

    }
}

    // Method to Check Our app is running or Not
    public static boolean isAppSentToBackground(final Context context) {

    try {
        ActivityManager am = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        // The first in the list of RunningTasks is always the foreground
        // task.
        RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
        String foregroundTaskPackageName = foregroundTaskInfo.topActivity
                .getPackageName();// get the top fore ground activity
        PackageManager pm = context.getPackageManager();
        PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(
                foregroundTaskPackageName, 0);

        String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo
                .loadLabel(pm).toString();

        // Log.e("", foregroundTaskAppName +"----------"+
        // foregroundTaskPackageName);
        if (!foregroundTaskAppName.equals("Your App name")) {
            return true;
        }
    } catch (Exception e) {
        Log.e("isAppSentToBackground", "" + e);
    }
    return false;
}

这段代码是错误的。不要使用它,它非常低效,并且getRunningTasks不适用于使用。从文档中可以看到:注意:此方法仅用于调试和呈现任务管理用户界面。这永远不应该用于应用程序的核心逻辑,例如根据此处找到的信息决定不同行为之间的区别。这样的用法是不受支持的,并且将来可能会出现问题。 - Martin Marconcini
@MartínMarconcini,我提供了我在我的应用程序中使用的解决方案,如果您不想使用,那就是您的选择。而且它可以在所有2.2到4.4版本的操作系统上完美运行。 - Smit Patel
1
这个解决方案可能能够工作,但是它在很多方面都是错误的。你是想使用一个错误的解决方案还是只是想要绕过问题并继续前进?文档明确地说不要使用这个解决方案。很抱歉,我来这里是为了通过向他人学习和教授他人来编写更好的代码。 - Martin Marconcini
如果这个方法是错误的,那为什么 Google 还会将其添加到文档中呢? - Smit Patel
当您阅读文档时,请注意粗体字中的文本,其中写着:“注意:此方法仅用于调试和呈现任务管理用户界面。” 然后他们明确表示:这绝不能用于应用程序的核心逻辑(强调是我的)。请注意,我甚至还没有开始谈论效率...那是另一个主题,不再属于这里。 - Martin Marconcini
显示剩余2条评论

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