Critical services

If we are running a task and it needs to complete as soon as possible, we can prevent the device's CPU from going to sleep. This allows the task to finish without interruption.

How to do it...

To prevent the CPU from going to sleep, we can use a wake lock:

  1. We will need to ensure that the Xamarin Support Library v4 NuGet or component is installed into the project if we are going to be using the WakefulBroadcastReceiver type.
  2. Before we can prevent the CPU from going to sleep with a wake lock, we need permission to do so:
    [assembly: UsesPermission(Manifest.Permission.WakeLock)]
  3. The recommended way to get hold of a wake lock is to use an instance of WakefulBroadcastReceiver and invoke the StartWakefulService() method:
    [BroadcastReceiver]
    public class CriticalReceiver : WakefulBroadcastReceiver {
      public override void OnReceive(
      Context context, Intent intent) {
        var serviceIntent = new Intent(
          context, typeof(CriticalService));
        StartWakefulService(context, serviceIntent);
      }
    }
  4. The service will then perform the task and invoke the CompleteWakefulIntent() method:
    [Service]
    public class CriticalService : IntentService {
      protected override void OnHandleIntent (Intent intent) {
        try {
          // perform the task
        }
        finally {
          WakefulBroadcastReceiver.CompleteWakefulIntent(
            intent);
        }
      }
    };
  5. If the receiver needs to be executed manually, we can do so with the SendBroadcast() method on the activity:
    SendBroadcast(new Intent(this, typeof(CriticalReceiver)));
  6. There is also another way to obtain a wake lock, which is using the PowerManager instance and requesting a lock with the NewWakeLock() method:
    var manager = PowerManager.FromContext(this);
    var wakeLock = manager.NewWakeLock(
      WakeLockFlags.Partial, "WakeLockTag");
    wakeLock.Acquire();
    try {
      // perform the task
    }
    finally {
      wakeLock.Release();
    }

How it works...

Some tasks are critical and need to be finished as soon as possible and as fast as possible. Normally, if the device is left idle, the screen and then the CPU turn off. Turning off various pieces of hardware is a great way to preserve battery life, but it also prevents some important tasks from completing until the CPU is awoken by the user.

If we have a task that is important to finish in a timely fashion, we can prevent the CPU from turning off by obtaining a wake lock. This is done by either using the recommended way of a WakefulBroadcastReceiver instance or by manually acquiring a wake lock from the PowerManager instance.

Using a WakefulBroadcastReceiver instance is very useful when the task comes from push notifications, as this will wake the CPU so that the message can be handled before going back to sleep. We just have to add the Xamarin Support Library v4 NuGet or component into our project, and then instead of inheriting from BroadcastReceiver, we inherit from the WakefulBroadcastReceiver type. This will automatically acquire a wake lock and we just have to implement the task we want to perform.

As the WakefulBroadcastReceiver instance is just an extended BroadcastReceiver instance, we cannot execute long-running or asynchronous tasks. If we wish to perform a task, we start that task in a service using the static StartWakefulService() method. We pass an Intent instance to this method, which specifies the service to start. Once the service has completed, we invoke the static CompleteWakefulIntent() method on the WakefulBroadcastReceiver type.

It is important to release the wake lock and to do it as soon as possible to avoid battery drain. In the case of exceptions, wrapping the execution of the task in a try/finally block will ensure that even if a problem occurs, the wake lock is released. This is important because even if the user presses the power button when a wake lock is being held, the CPU will not go to sleep.

Tip

The task should be wrapped in a try/finally block to ensure that the wake lock is always released. This ensures that there will be no unnecessary battery consumption due to an exception.

If the task does not need to be in a broadcast receiver or a service, we can acquire a wake lock directly from the PowerManager instance. This is simple to implement by first obtaining the PowerManager instance through the FromContext() method. Then, we request a new wake lock using the NewWakeLock() method. This method takes two parameters, the wake lock type and the tag that is used in debugging.

There are several types of wake locks, some of which keep the screen on. If we want to keep just the CPU awake, we use the Partial value of the WakeLockFlag enumeration.

Once we have the wake lock, we have to acquire the actual lock by invoking the Acquire() method. After invoking this method, the device's CPU is guaranteed not to turn off until we invoke the Release() method. As the wake is not released until explicitly instructed, it is best to wrap the task in a try/finally block to ensure that the wake lock will always be released.

There's more...

Some critical services don't need to run continuously, but rather once every few minutes. We can do this by setting up an alarm, and in this case, a repeating alarm, to broadcast an intent for our broadcast receiver:

var intent = new Intent(this, typeof(CriticalReceiver));
intent.PutExtra(CriticalService.DataKey, "Using alarm manager.");
var pending = PendingIntent.GetBroadcast(ApplicationContext, 123, intent, 0);
var manager = AlarmManager.FromContext(this);
manager.SetRepeating(AlarmType.RtcWakeup, 0, 30*1000, pending);

When the alarm triggers, it will wake the device and broadcast the intent. The broadcast receiver will then acquire a wake lock and start the service.

..................Content has been hidden....................

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