We may require a single service to be able to handle multiple requests from multiple sources simultaneously.
If we want a service to be able to handle multiple requests simultaneously, we inherit from the Service
type, which provides the required features:
Service
:[Service] public class XamarinService : Service { public override StartCommandResult OnStartCommand( Intent intent, StartCommandFlags flags, int startId) { return StartCommandResult.Sticky; } public override IBinder OnBind(Intent intent) { return null; } }
private int started = 0; private async void ProcessRequest() { started++; await Task.Run (() => { // do the work for this particular request // ... StopSelf (startId); }); started--; if (started == 0) StopSelf(); }
OnStartCommand()
method is invoked, we can start a new batch of work:ProcessRequest();
StartService(new Intent(this, typeof(XamarinService));
When we need our service to handle multiple requests simultaneously, we need to inherit from the base Service
type. Instead of the requests being queued and executed one at a time, each request reaches the OnStartCommand()
method immediately.
When handling an Intent
instance in the OnStartCommand()
method, we can decide to do whatever we want. Usually, the task can be started in this method. But, where this differs from a ServiceIntent
instance is the creation of a new thread. The ServiceIntent
instance creates a new thread and executes the OnHandleIntent()
method on that new thread. The base Service
instance does not do this, but rather executes on the UI thread. We have to manually create a new thread for execution.
The OnStartCommand()
method returns a StartCommandResult
instance value that specifies what the system is to do in the event that the service is terminated before the execution is complete. We can request that the service should not be restarted, or we can request that the service is restarted with or without the original intent:
Return value |
Effect |
Use |
---|---|---|
|
This does not restart the service if it is terminated unless there are more intents to still be delivered. |
When the app can simply restart any unfinished jobs. |
|
This restarts the service, but uses a |
When the service is not performing tasks but rather waiting for incoming jobs. |
|
This restarts the service with the last intent. |
When the service is performing a task that needs to be immediately retried. |
If the service is performing specific tasks, it is important that the service is stopped using StopSelf()
when all the tasks are complete. We have to keep track of when services start and finish and then stop the service when the work is done. We can make use of the startId
instance provided by the OnStartCommand()
method and pass that to StopSelf()
. However, we still have to ensure that we do not invoke StopSelf()
with the most recent ID while some tasks are still being processed. If we do, the service will be terminated anyway and the threads will be leaked.
The OnBind()
method is not required to be implemented and can safely return null
. This method is used when connecting to the service directly. There is more information on this in the Communicating with running services recipe.
We can start the service multiple times, and multiple threads will be created from the thread pool. Each thread will perform the task and then stop. Once all the tasks have finished, the service should be terminated.