How to check if a service is running on Android?

2018-12-31 02:29发布

How do I check if a background service (on Android) is running?

I want an Android activity that toggles the state of the service -- it lets me turn it on if it is off and off if it is on.

23条回答
荒废的爱情
2楼-- · 2018-12-31 02:46

This is an extract from Android docs:

Like sendBroadcast(Intent), but if there are any receivers for the Intent this function will block and immediately dispatch them before returning.

Think of this hack as "pinging" the Service since we can broadcast syncronously we can broadcast and get a result -- synchronously -- on the UI thread.

Service

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), IntentFilter("ping");
}

private class ServiceEchoReceiver{
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("pong"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
        if(!serviceRunning){
           //try and run the service
        }
    }

    private BroadcastReceiver pong = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }
查看更多
倾城一夜雪
3楼-- · 2018-12-31 02:47

I had the same problem not long ago. Since my service was local, I ended up simply using a static field in the service class to toggle state, as described by hackbod here

EDIT (for the record):

Here is the solution proposed by hackbod:

If your client and server code is part of the same .apk and you are binding to the service with a concrete Intent (one that specifies the exact service class), then you can simply have your service set a global variable when it is running that your client can check.

We deliberately don't have an API to check whether a service is running because, nearly without fail, when you want to do something like that you end up with race conditions in your code.

查看更多
无与为乐者.
4楼-- · 2018-12-31 02:47

I use the following from inside an activity:

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

And I call it using:

isMyServiceRunning(MyService.class)

This works reliably, because it is based on the information about running services provided by the Android operating system through ActivityManager#getRunningServices.

All the approaches using onDestroy or onSometing events or Binders or static variables will not work reliably because as a developer you never know, when Android decides to kill your process or which of the mentioned callbacks are called or not. Please note the "killable" column in the lifecycle events table in the Android documentation.

查看更多
栀子花@的思念
5楼-- · 2018-12-31 02:47

Xamarin C# version:

private bool isMyServiceRunning(System.Type cls)
{
    ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);

    foreach (var service in manager.GetRunningServices(int.MaxValue)) {
        if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
            return true;
        }
    }
    return false;
}
查看更多
若你有天会懂
6楼-- · 2018-12-31 02:49

For the use-case given here we may simply make use of the stopService() method's return value. It returns true if there exists the specified service and it is killed. Else it returns false. So you may restart the service if the result is false else it is assured that the current service has been stopped. :) It would be better if you have a look at this.

查看更多
一个人的天荒地老
7楼-- · 2018-12-31 02:51

Got it!

You MUST call startService() for your service to be properly registered and passing BIND_AUTO_CREATE will not suffice.

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

And now the ServiceTools class:

public class ServiceTools {
    private static String LOG_TAG = ServiceTools.class.getName();

    public static boolean isServiceRunning(String serviceClassName){
        final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
        final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        for (RunningServiceInfo runningServiceInfo : services) {
            if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
                return true;
            }
        }
        return false;
     }
}
查看更多
登录 后发表回答