Handling simultaneous service requests

We may require a single service to be able to handle multiple requests from multiple sources simultaneously.

How to do it...

If we want a service to be able to handle multiple requests simultaneously, we inherit from the Service type, which provides the required features:

  1. We first need a type that inherits from 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;
      }
    }
  2. Now, we can create a method that handles multiple requests:
    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();
    }
  3. Each time the OnStartCommand() method is invoked, we can start a new batch of work:
    ProcessRequest();
  4. Then, we can start the service multiple times if required:
    StartService(new Intent(this, typeof(XamarinService));

How it works...

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.

Note

The OnStartCommand() method executes on the UI thread. Unlike the OnHandleIntent() method, a new thread must be created manually.

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

NotSticky

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.

Sticky

This restarts the service, but uses a null intent if there are no more intents to deliver.

When the service is not performing tasks but rather waiting for incoming jobs.

RedeliverIntent

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.

See also

  • The Starting services recipe
  • The Communicating with running services recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset