Staying awake with WakeLocks

Earlier in this chapter we learned that we can use a BroadcastReceiver to handle alarms, and even do work in the background for up to 10 seconds, though only on devices running API level 11 or greater.

In the previous section, we saw that handling alarms directly with services is not a reliable solution for scheduling long-running work, since there is no guarantee that our Service will start up before the device returns to sleep.

We have a problem! If we want to perform long-running work in response to alarms, we need a solution that overcomes these limitations.

What we really want is to start a Service to handle the work in the background, and to keep the device awake until the Service has finished its work. Fortunately, we can do that by combining the wakefulness guarantees of BroadcastReceiver to get the Service started, then keep the device awake with explicit power management using PowerManager and WakeLock.

As you might guess, WakeLock is a way to force the device to stay awake. WakeLocks come in various flavors, allowing apps to keep the screen on at varying brightness levels or just to keep the CPU powered up in order to do background work. To use WakeLocks, our application must request an additional permission in the manifest:

<uses-permission android:name="android.permission.WAKE_LOCK" />

To keep the CPU powered up while we do background work in a Service, we only need a partial WakeLock, which won't keep the screen on, and which we can request from the PowerManager like this:

PowerManager pm = (PowerManager) 
    ctx.getSystemService(Context.POWER_SERVICE);
WakeLock lock = pm.newWakeLock(
    PowerManager.PARTIAL_WAKE_LOCK, "my_app");
lock.acquire();

We'll need to acquire a WakeLock during our BroadcastReceiver's onReceive method, and find some way to hand it to our Service so that the Service can release the lock once its work is done.

Unfortunately, WakeLocks are not parcelable, so we can't just send them to the Service in an Intent. The simplest solution is to manage the WakeLock instance as a static property that both the BroadcastReceiver and the target Service can reach.

This is not difficult to implement, but we don't actually need to implement it ourselves—we can use the handy v4 support library class, WakefulBroadcastReceiver.

WakefulBroadcastReceiver exposes two static methods that take care of acquiring and releasing a partial WakeLock. We can acquire the WakeLock, and start the Service with a single call to startWakefulService:

ComponentName startWakefulService(Context context, Intent intent);

And when our Service has finished its work, it can release the WakeLock with the corresponding call to completeWakefulIntent:

boolean completeWakefulIntent(Intent intent);

Since these methods are static, we don't need to extend WakefulBroadcastReceiver to use them. Our BroadcastReceiver just needs to start the Service using startWakefulService:

class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent serviceIntent = new Intent(
            context, MyIntentService.class);
        WakefulBroadcastReceiver.startWakefulService(
            context, serviceIntent);
    }
}

We must make sure to release the WakeLock once the Service has finished its work, otherwise we'll drain the battery by keeping the CPU powered up unnecessarily:

class MyIntentService extends IntentService {
    @Override
    protected final void onHandleIntent(Intent intent) {
        try {
            // do background work while the CPU is kept awake
        } finally {
            WakefulBroadcastReceiver.
                completeWakefulIntent(intent);
        }
    }
}

This is great—by using a statically registered BroadcastReceiver we've ensured that we receive the alarm, even if our application is not running when the alarm comes due. When we receive the alarm we acquire a WakeLock, keeping the device awake while our Service starts up and does its potentially long-running work. Once our work is done, we release the WakeLock to allow the device to sleep again and conserve power.

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

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