FVod FVod - 12 days ago 5
Android Question

Using Service as singleton in Android

Is it a bad practice to create a

Service
that works as a singleton? I mean a
Service
that is never stopped and that contains some private data that some other engines and
Activities
would use, so the
Service
could have something like:

public class CustomService extends Service {
private List<Profile> mProfiles;
private static CustomService instance;

public static CustomService getInstance() {
if(instance == null) {
instance = new CustomService();
}
return instance;
}

public List<Profile> getProfiles() {
return mProfiles;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
}
...
}


The reason of doing a
Service
instead of just a singleton is that it must work independently of the application, as when it starts it connects a websocket that should never be closed and do not depend on the application. What would you suggest me to do? Is there a better way to re-use the
Service
in order to have some data (for instance the
mProfiles
array) available from other engines and
Activities
?

I've read somewhere that a
Service
works as a singleton, but I don't know how to access the private variables from any other point in application.

Thanks in advance.

Answer

Is it a bad practice to create a service that works as a singleton?

It is redundant and, in the way you suggest, not going to work from the point of view of Android Service as application component which is to perform its functionality with respect to

  • Application lifecycle that, in its turn, affected by
  • system events.

Such an intention of an application component is reached by

  • its declaration in the AndroidManifest.xml,
  • triggering it (starting / binding / registering) and
  • creating (by the system) an instance of the component within Application and "attaching" it to ApplicationThread/ActivityThread.

That said, brings to the fact that application components are tied to the Application instance hosted by OS process and can't run independently.


Regarding your approach, there are two scenarios:

1. CustomService's default constructor is private as per the pattern.

By calling getInstance() a single instance of CustomService is created. The instance is just a Java object (singleton) that has nothing in common with Android Service application component. The onStart(), onStartCommand() etc. methods will never be called by the system.

An attempt to start the "service" (declared in the manifest) with startService(Intent) will fail with IllegalAccessException: access to constructor not allowed.

2. CustomService's default constructor is public (as per the code posted).

If the service is declared in AndroidManifest and the default constructor is empty, startService() won't fail, however getInstance() will create another instance of CustomService that won't be treated as Android Service application component.

This isn't a singleton.


What would you suggest me to do? Is there a better way to re-use the service in order to have some data (for instance the mProfiles array) available from other engines and activities?

Use Service as per the documentation and pick the kind of communication you need:

  • One-way communication (Activity --> Service) - use a started Service and handle each Intent (with your data attached to it, like mProfiles in case Profile class implements Parcelable) in onStartCommand();
  • Two-way communication (Activity <-> Service) - use a bound Service and communicate via IBinder.

Finally, Service in Android is a singleton. There is only one instance of each service in the system. It starts on demand and handles all pending Intents / bound clients. Once it's done or explicitly stopped, it will be destroyed.

Comments