Services accompany us in Android from the first day. Even so, many of the applications we make do not need them, or use them very superficially. Therefore, for many developers services have become a little mystery. This post is the first of a series in which we will describe in detail, and with a certain revisionist spirit, the possibilities offered by the Service class and its partners in the platform.
A little bit of Context
Service was born as one of the fundamental components of the Android application programming interface (API). By then the term component was used explicitly to refer to four elements of the framework: Activity, Service, ContentProvider and BroadcastReceiver. Currently the use of the word component seems to be blurred in the official documentation, but the features that make these elements special remain valid.
On the one hand, they are all managed components: classes designed to be extended and whose instances should not be used in any way in the applications, but must be adapted to a predefined and system-driven life cycle. We do not create objects from our Activity, Service or ContentProvider classes, we start them indirectly using Intents or ContentResolvers. We do not execute methods in ourBroadcastReceiver, we register them and wait for them to receive calls in their onReceive(…) method.
Secondly, these four classes are those providing context into our code. Literally, they are the ones allowing to access to objects of the Context class, fundamental for applications to access device resources or system services. Activity and Service are contexts themselves, since they extend the Context class. ContentProvider gives access to an immutable context with its getContext() method, and BroadcastReceiver receives it as an onReceive(…) parameter.
Because of this, the components have a heavy weight in the structure of our apps. Each of them has unique characteristics that endow them with a differentiated purpose. Let’s see which is that of services.
Born to serve
A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface. Another application component can start a service, and it continues to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service can handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
The first line clearly defines the mission of services in Android: perform long-running operations. To do this, and in direct opposition to the mission of an Activity, a Service does not provide a user interface, or in other words, it does not depend on a user interface.
What long-running operations can be of interest to us on a mobile device? Think of an application like ownCloud,, which allows access, manage and share files in our private cloud. The ownCloud app runs tasks that require downloading or uploading files to a remote ownCloud server. Typically, a user who wants to upload, for example, multiple videos from their mobile to their ownCloud account will prefer to leave the application and go on with her life, rather than patiently look at the progress bar with the app open while the transfer is complete.
Fortunately, we have Service to help us implement this type of work. The Activity class is not appropriate because it is designed to provide a user interface to which it is intimately linked. An instance of Activity, in general, should interrupt or pause any work that runs in the background when the user removes it from the screen.
And what does a Service provide that an Activity does not to ease our life as developers of long tasks? The fundamental difference lies in their life cycle. When we want to develop a service, we must write a class that extends to the Service class or one of its heirs. In doing so, we will have to overload certain Service-specific methods that will be called in our application in response to requests from components acting as service clients. In these methods we will have to start the execution of the tasks to be executed. The Android framework is committed, through the specification of Service life cycle, not to interrupt the operation of the service even if the customers that start operations on it are removed, unless certain conditions are met.
Is this sufficient to develop long-running operations? Of course it is necessary, but we must be careful with what the Service class does not provide. Although its mission is the execution of tasks in background, the vast majority of its entry methods are executed by the framework in the main thread of the application, and not in a thread in background, as would be easy to take on. Android leaves to our responsibility to ensure that the tasks will run on other threads to release the main thread and grant the app will work properly.
Three are Three
After the definition, the development guide describes three types of services, although perhaps it is more accurate to think of three ways of executing them.
The classic modes of execution are those of started service and bound service. Started services support the fundamental mission of the Service class, since in this mode of operation the service will remain active indefinitely until it indicates that it has finished its work or until another component explicitly stops it (1) .
On the other hand, bound services offer the possibility that one or several client components obtain an object reference to interact directly with the service, through a regular Java interface, instead of with asynchronous requests launched via Intents. Bound services will not run indefinitely, instead they will be interrupted when all their client components are unbound. This goes against the interest of the Service to execute tasks independently of its clients, but it is easy to solve since the same service can be executed in both started and bound modes at the same time.
The third mode of operation is that of scheduled services. It was incorporated with Android 5 (API level 21), and Google expressly recommends it for all devices that support it. Its brings a drastic change to our applications, since scheduled services are not executed immediately after client requests. A request for a scheduled job includes some conditions that must be true before performing the work. The framework guarantees that the service will not attempt to run without these conditions being met, but does not undertake to do so as soon as they are met.
To be continued
In next installments of this series we will study more details on how the three modes of execution of a Service work, how we can take advantage of each one and how their different constrains can affect to our apps .
(1) In conditions of scarce resources, the system may decide to kill the process that executes a started service. This is considered an exceptional behaviour