9

I had some functionalities of my app broken once upgrading to Android 8, even not targeting the API 26 explicitly. In particular, the good old function to check if a Service is running (as documented on StackOverflow here: How to check if a service is running on Android?) is not working anymore.

Just to refresh our collective memory, it was this classic method:

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;
}

The problem now is that getRunningServices is now deprecated and doesn't return the running services anymore. Does anyone have experience with this issue on Android 8? Is there any official solution (or hack) available? I should also point out that the Service I want to look for is not in the same process/app as the code that is calling isMyServiceRunning() (that functionality is still provided for backward compatibility reasons)

Enrico Casini
  • 171
  • 2
  • 7
  • IMHO, ideally your other code neither knows nor cares whether the service is running. I find this `isMyServiceRunning()` sort of thing is a code smell. That being said... if this service is in the same process as whatever is calling `isMyServiceRunning()`, use a `static` `boolean` value, set in `onCreate()` and cleared in `onDestroy()` of the service . Check the `boolean` to see if the service is running. If this service is in a different process, and you are using the binding pattern, bind to the service without `BIND_AUTO_CREATE`. – CommonsWare Jan 29 '18 at 17:44
  • @CommonsWare I agree with your opinion about the smelly code. The problem here is that I need to use it to check a service of a third party application (which still happens to be mine). So the Service is **not** in the same process as the code calling `isMyServiceRunning()`, maybe I should specify it in my question. – Enrico Casini Jan 29 '18 at 17:47
  • 1
    this is what one of android architect said: https://groups.google.com/forum/#!topic/android-developers/jEvXMWgbgzE `"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."` – pskink Jan 29 '18 at 17:50
  • 1
    "The problem here is that I need to use it to check a service of a third party application" -- why do you care if the service is running or not? Suppose that your `isMyServiceRunning()` returns `true` -- what do you do? Suppose that it returns `false` -- what do you do? – CommonsWare Jan 29 '18 at 18:15
  • and what if `isMyServiceRunning` returns `false` but in the meantime the service is started? – pskink Jan 29 '18 at 18:25
  • @CommonsWare and pskink, I simply need to connect to another app if the Service is running. So I want to display whether the Service is running on not and change the UI accordingly to allow to connect and/or start the service if it's not running. For now, I will just do a workaround and check if the specific TCP port of my Service is bound. – Enrico Casini Jan 29 '18 at 20:09
  • @pskink it will work anyway, it will just try to start something already started (via Intent). There is no way it could happen, even though theoretically still possible, practically it isn't. – Enrico Casini Jan 29 '18 at 20:48
  • I like the idea with bound services. Your app A will bind to a service in app B essentially making that service "standby" if it isn't already started and doing work. This will require an AIDL interface and both apps will need to be updated. – Eugen Pechanec Jan 29 '18 at 20:51
  • 1
    you should not depend on the "physical" state of your service (started / not started) but rather on its "logical" state (say it connected / not connected) - you can easily check that state by calling (unconditionally) `startService` and passing via `Intent` extras either `ResultReceiver` or `Messenger` object and inside `Service#onStartCommand` simply respond with the current state – pskink Jan 30 '18 at 06:21
  • Possible duplicate of https://stackoverflow.com/questions/45715905/android-o-replacement-for-getrunningservices – JoeyG Apr 01 '19 at 13:54

1 Answers1

5

getRunningServices() this method is no longer available to third party applications. there's no substitute method for getting the running service.

https://developer.android.com/reference/android/app/ActivityManager.html#getRunningServices(int)

How to check if a service is running on Android?) I just check it manually , I put Boolean true when service is running and false when the service stopped or destroyed. I'm using SharedPreferences to save the Boolean value.

Service.class

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
    Log.d("service", "onStartCommand")
    setRunning(true)
}

private fun setRunning(running: Boolean) {
    val sessionManager = SessionManager(this)
    sessionManager.isRunning = running
}


override fun onDestroy() {
   setRunning(false)
   super.onDestroy()
}

SessionManager.class

class SessionManager(var context: Context) {
    private val loginpreferences: SharedPreferences
    private val logineditor: SharedPreferences.Editor

    init {
      loginpreferences = context.getSharedPreferences(Pref_name, private_modde)
      logineditor = loginpreferences.edit()
    }

    var isRunning: Boolean
      get() = loginpreferences.getBoolean(SERVICES, false)
      set(value) {
         logineditor.putBoolean(SERVICES, value)
         logineditor.commit()
      }

    companion object {
      private val SERVICES = "service"
    }

}
Exel Staderlin
  • 535
  • 7
  • 10