所谓后台,我的意思是应用程序的活动目前对用户都不可见?


当前回答

我认为这个问题应该更清楚。什么时候?在哪里?你想知道应用是否处于后台的具体情况是什么?

我只是用我的方法介绍我的解决方案。 我通过在我的应用程序中的每个活动的onStop方法中使用RunningAppProcessInfo类的字段“重要性”来完成这一点,这可以简单地通过为其他活动提供一个BaseActivity来扩展,实现onStop方法来检查“重要性”的值。代码如下:

public static boolean isAppRunning(Context context) {
    ActivityManager activityManager = (ActivityManager) context
        .getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager
        .getRunningAppProcesses();
    for (RunningAppProcessInfo appProcess : appProcesses) {
        if (appProcess.processName.equals(context.getPackageName())) {
            if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
                return true;
            } 
        }
    }
    return false;
}

其他回答

您应该使用共享首选项来存储属性,并使用来自活动的服务绑定对其进行操作。如果你只使用绑定(也就是从不使用startService),那么你的服务将只在你绑定它时运行,(绑定onResume和取消绑定onPause),这将使它只在前台运行,如果你确实想在后台工作,你可以使用常规的启动停止服务。

除非你自己跟踪它,否则无法确定你的任何活动是否可见。也许你应该考虑问一个新的StackOverflow问题,解释一下你想从用户体验中获得什么,这样我们也许可以给你其他的实现想法。

在我看来,许多答案引入了大量的代码,带来了很多复杂性和可读性。

当人们问SO如何在服务和活动之间通信时,我通常建议使用LocalBroadcastManager。


Why?

我引用一下医生的话:

你知道你广播的数据不会离开你的应用程序,所以不需要担心泄露私人数据。 其他应用程序不可能将这些广播发送到你的应用程序,所以你不需要担心他们可以利用的安全漏洞。 这比通过系统发送全球广播更有效。

文档里没有:

它不需要外部库 代码是最少的 它易于实现和理解 没有自定义的自实现回调/超单例/进程内 任何模式…… 没有对Activity, Application,…


描述

你想要检查是否有Activity当前在前台。您通常在服务或应用程序类中这样做。

这意味着,您的Activity对象成为信号的发送者(I'm on / I'm off)。另一方面,您的服务成为接收者。

Activity有两个时刻告诉你它是在前台还是在后台(是的,只有两个…不是6)。

当Activity进入前台时,onResume()方法被触发(也在onCreate()之后调用)。

当Activity回到后面时,onPause()被调用。

在这些时刻,您的活动应该向您的服务发送信号,以描述其状态。

在有多个Activity的情况下,记住一个Activity先进入后台,然后另一个进入前台。

所以情况是:*

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

服务/应用程序将简单地监听这些信号并进行相应的操作。


代码(TLDR)

你的服务必须实现一个BroadcastReceiver来监听信号。

this.localBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // received data if Activity is on / off
    }
}

public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

在服务中注册接收者::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

在Service::onDestroy()中取消注册

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

现在你的Activity必须传达它们的状态。

在活动::onResume ()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

在活动::onPause ()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

这是一种非常非常常见的情况

开发人员:我想从我的服务发送数据并更新活动。我如何检查活动是否在前景?

通常不需要检查Activity是否在前台。只需从服务中通过LocalBroadcastManager发送数据。如果活动处于开启状态,那么它将做出响应并采取行动。

对于这种非常常见的情况,服务成为发送方,活动实现BroadcastReceiver。

因此,在您的活动中创建一个Receiver。在onResume()中注册,在onPause()中取消注册。不需要使用其他生命周期方法。

在onReceive()中定义Receiver行为(更新ListView,做这个,做那个,…)

这样Activity只会在它在前台的时候监听,如果它在后面或者被销毁了什么也不会发生。

在多个活动的情况下,任何一个活动都将响应(如果它们也实现了Receiver)。

如果所有人都在后台,没有人会回应,信号就会丢失。

通过Intent(见上面的代码)通过指定信号ID从服务发送数据。


除了多窗口支持。这可能很棘手(如果需要,请测试它)…

根据CommonsWare和Key所说的,你可以扩展Application类,并让你所有的活动在onPause/onResume方法上调用它。这将允许您知道哪些活动是可见的,但这可能会得到更好的处理。

你能详细说明一下你的想法吗?当你说在后台运行,你的意思是简单地让你的应用程序仍然在内存中,即使它目前不在屏幕上?你有没有考虑过使用服务作为一种更持久的方式来管理你的应用程序,当它不在焦点?

由于没有提到它,我将建议读者探索通过Android架构组件提供的ProcessLifecycleOwner