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. For example, a service can handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
These are the three different types of services
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn’t interacting with the app.
A background service performs an operation that isn’t directly noticed by the user. For example, if an app used a service to compact its storage, that would usually be a background service.
A service is bound when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, receive results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
First we will create a MainApplication class, what extends the Application class. Starting in Android 8.0 (API level 26), all notifications must be assigned to a channel. For each channel, you can set the visual and auditory behavior that is applied to all notifications in that channel. Then, users can change these settings and decide which notification channels from your app should be intrusive or visible at all. To create a notification channel, follow these steps.
- Construct a NotificationChannel object with a unique Channel ID, a user- visible name, and an importance level.
- Optionally, specify the description that the user sees in the system settings with setDescription().
- Register the notification channel by passing it to createNotificationChannel().
We will implement in the MainApplication::class the NotificationChannel so at the startup of the app the channel will be created.
Channel ID: This will identify the notification. Later on we can update it with this.
Importance level: Channel importance affects the interruption level of all notifications posted in the channel, and you must specify it in the NotificationChannel constructor. You can use one of five importance levels, ranging from IMPORTANCE_NONE(0) to IMPORTANCE_HIGH(4). The importance level you assign to a channel applies to all notification messages that you post to it.
Our MainApplication::class will be in the same package like the MainActivity::class.
After the implementation of the MainApplication, we have add it to the AndroidManifest.xml.
The next step is to create the activity_main.xml.
We will have there one EditText as an input type of the notification.
The next two views are two Buttons to start and stop our foreground service.
We will align this views with ConstraintLayout.
To create a service, we must create a subclass of Service or use one of its existing subclasses. In the implementation, we must override some callback methods that handle key aspects of the service lifecycle and provide a mechanism that allows the components to bind to the service, if appropriate.
These are the most important callback methods that you should override
The system invokes this method by calling startService() when
another component (such as an activity) requests that the service
be started. When this method executes, the service is started and can run in the background indefinitely. If you implement this, it is your responsibility to stop the service when its work is complete by calling stopSelf() or stopService(). If you only want to provide binding, you don’t need to implement this method.
The system invokes this method by calling bindService() when another component wants to bind with the service (such as to perform RPC). In the implementation of this method, we must provide an interface that clients use to communicate with the service by returning an IBinder. We must always implement this method; however, if we don’t want to allow binding, it should return null.
The system invokes this method to perform one-time setup procedures when the service is initially created (before it calls either onStartCommand() or onBind()).
If the service is already running, this method is not called.
The system invokes this method when the service is no longer used and is being destroyed. The service should implement this to clean up any resources such as threads, registered listeners, or receivers.
This is the last call that the service receives.
And here it is, our ForegroundService::class
We must declare all services in the application’s manifest file,
just as we did for the MainActivity.
To declare the service, we will add a <service> element as a
child of the <application> element.
Notice that the onStartCommand() method must return an integer. The integer is a value that describes how the system should continue the service in the event that the system kills it. The default implementation for IntentService handles this for you, but you are able to modify it.
The return value from onStartCommand() must be one of the following constants
If the system kills the service after onStartCommand() returns, do not recreate the service unless there are pending intents to deliver. This is the safest option to avoid running our service when not necessary and when your application can simply restart any unfinished jobs.
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent unless there are pending intents to start the service. In that case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands but are running indefinitely and waiting for a job.
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file.
The last step is our MainActivity::class. From here we will start our service and later can finish it also.
Starting a service
You can start a service from an activity or other application component by passing an Intent to startService() or startForegroundService(). The Android system calls the service’s
onStartCommand() method and passes it the Intent, which specifies which service to start.
Stopping a service
A started service must manage its own lifecycle. That is, the system doesn’t stop or destroy the service unless it must recover system memory and the service continues to run after onStartCommand() returns. The service must stop itself by calling stopSelf(), or another
component can stop it by calling stopService().
Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as possible.