如何确定Android服务是否在前台运行?

37

我有一个服务,我认为它正在前台运行,如何检查我的实现是否有效?

7个回答

41
public static boolean isServiceRunningInForeground(Context context, Class<?> serviceClass) {
      ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
      for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
         if (serviceClass.getName().equals(service.service.getClassName())) {
            if (service.foreground) {
               return true;
            }

         }
      }
      return false;
   }

7
与被接受的回答相比,我发现这个答案中的代码更整洁,而且即使有超过50个服务在运行,它也能正常工作。 - Sam
3
好的,我会尽力做到最好。以下是需要翻译的内容:与已接受的相同但更加清晰、简短和简单。还要检查所有服务,而不仅仅是50个。 - Sergio
1
这里唯一的问题是:“自安卓8.0起,第三方应用程序将无法使用此方法。为了向后兼容,它仍将返回调用者自己的服务。” - diesersamat
@diesersamat 那么你有什么建议? - Jason Krs
1
如果我想在Android O中做同样的事情怎么办? - Jason Krs
2
getRunningServices在Android 9中已被弃用。 - LukaszTaraszka

33
private boolean isServiceRunning(String serviceName){
    boolean serviceRunning = false;
    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningServiceInfo> l = am.getRunningServices(50);
    Iterator<ActivityManager.RunningServiceInfo> i = l.iterator();
    while (i.hasNext()) {
        ActivityManager.RunningServiceInfo runningServiceInfo = i
                .next();

        if(runningServiceInfo.service.getClassName().equals(serviceName)){
            serviceRunning = true;

            if(runningServiceInfo.foreground)
            {
                //service run in foreground
            }
        }
    }
    return serviceRunning;
}

如果您想知道您的服务是否在前台运行,只需打开一些其他的大型应用程序,然后检查服务是否仍在运行,或者只需检查标志service.foreground


5
谢谢,这个方法很有效!我只需要加上这行代码:serviceInForeground = runningServiceInfo.foreground; - user811985
在onDestroy()中使用stopForeground(true)会怎么样?这不会停止服务在前台运行吗? - IgorGanapolsky
4
FYI,关于RunningServiceInfo.foreground的文档指出: "如果服务请求作为前台进程运行,则设置为true。"。也就是说,它并不告诉你Android是否实际接受了一个服务进入前台。http://developer.android.com/reference/android/app/ActivityManager.RunningServiceInfo.html#foreground - newbyca
2
很遗憾,GetRunningServices现在已被标记为弃用。 - MBentley

13

一个更高效的答案变体:https://dev59.com/eWw15IYBdhLWcg3wtN2O#36127260

public static boolean isServiceRunningInForeground(Context context, Class<?> serviceClass) {
   ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
   for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
      if (serviceClass.getName().equals(service.service.getClassName())) {
         return service.foreground;
      }
   }
   return false;
}

6

从API 26开始,getRunningService()已被弃用。

现在的解决方案是将Activity与Service绑定。然后你可以从Activity中调用Service的方法来检查它是否正在运行。

1 - 在你的Service中创建一个继承Binder类并返回你的Service的类。

  public class LocalBinder extends Binder {
        MyService getService() {
            return MyService.this;
        }
    }

2- 在您的服务中声明 binder

private final IBinder binder = new LocalBinder();

3 - 实现你的Service中的onBind()方法,它将返回Binder

  @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

4 - 在您的服务中,创建一个方法来检查它是否正在运行(例如检查变量是否已经初始化)

  public boolean isRunning() {
        // If running
            return true;
        // If not running
            return false;
        
    }

5 - 在您的Activity中创建一个变量来保存您的服务

private MyService myService;

6 - 现在,在您的Activity中,您可以绑定到您的Service

private void checkIfEnabled() {
    ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            MyService.LocalBinder binder = (MyService.LocalBinder) service;
            myService = binder.getService();
            
            // Calling your service public method
            if(myService.isRunning()) {
                // Your service is enabled
            } else {
                // Your service is disabled
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {

        }
    };

    // Bind to MyService
    Intent intent = new Intent(this, MyService.class);
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
}

要了解更多信息,请查看官方文档中的绑定服务概述


你好,请问能否分享一下isRunning函数的逻辑?如何在应用程序在后台运行了一个小时后并成功打开应用程序后检查服务是否正在运行。 - Anoop
1
如果活动/应用程序进程被清除了会怎样? - Zain

4

从API29(Q)开始,您可以使用以下代码简单地检查它。

可以从您的服务内部调用。如果您没有服务实例,您可以使用binder获取它。

class MyService : Service {
    val isForeground: Boolean get() = foregroundServiceType != FOREGROUND_SERVICE_TYPE_NONE
}

1
请注意,类型为FOREGROUND_SERVICE_TYPE_NONE只有在启动一次后才会出现。无论是否删除通知,调用stopForeground()仍将导致foregroundServiceType不是FOREGROUND_SERVICE_TYPE_NONE。我建议将getRunningService()答案之一(并检查foreground字段)合并,即使它已被弃用。 - technicalflaw
@technicalflaw 感谢您指出这一点。我其实不确定这是一个错误还是文档写得不好。我已经在 Google 追踪器上创建了一个问题(https://issuetracker.google.com/issues/261149524)。 - Peter
请注意,如果您调用stopSelf(),它将切换回FOREGROUND_SERVICE_TYPE_NONE,所以至少这一点是有效的。 - undefined

1

关于Adam的回答,稍作补充:

@Suppress("DEPRECATION") // Deprecated for third party Services.
fun <T> Context.isServiceForegrounded(service: Class<T>) =
    (getSystemService(ACTIVITY_SERVICE) as? ActivityManager)
        ?.getRunningServices(Integer.MAX_VALUE)
        ?.find { it.service.className == service.name }
        ?.foreground == true

0

这在加密货币新闻的Coinverse应用程序中对我起作用。

这是最简洁的Kotlin解决方案。感谢Abbas NaqdiGitHub问题中的贡献。

@Suppress("DEPRECATION") // Deprecated for third party Services.
fun <T> Context.isServiceRunning(service: Class<T>) =
        (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
            .getRunningServices(Integer.MAX_VALUE)
            .any { it.service.className == service.name }

如果您需要停止服务,这是适用于Android 9.0最新实现 - AdamHurwitz
2
问题是关于在前台运行的服务。因此,您还应该检查 it.foreground - Elyess Abouda

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