The good old times

Android was always a tolerant platform when it came to the background operations. As a developer, you could almost always assume that your background job will get performed, as long as you acquire proper wakelocks (ask your fellow iOS developers how envious they are of this). But what’s good for developers isn’t always good for users – such behavior favored poorly written apps that were killing users’ batteries by constantly keeping their devices up and running. Marshmallow’s Doze and App Standby concepts are Google’s picks to solve that problem once and for all.

Doze

The newest Android detects when your device is unplugged, not moving and has its screen turned off. Once all these requirements are met, Android will enter Doze mode after some time. This means no SyncAdapter and no JobScheduler will perform. Also, AlarmManager’s functionality will be limited when in Doze, but you can bypass this behavior if you really (but REALLY) need it.

No worries, it doesn’t mean your sync requests or delayed JobScheduler’s tasks will be ignored. They’ll get batch executed once Android exits Doze mode for a maintenance window (which, according to my research, results in approximately 5-10 minutes of possible networking).

Maintenance windows in Doze won’t happen frequently. First window occurs an hour after last activity, the next after two, the next after four and so on. But it doesn’t matter that much since user isn’t even moving her device anyway.

App Standby

From a single app’s perspective, App Standby isn’t much different from Doze. Basically, what Doze does on a system-wide level, App Standby does on a single app level. This means Android 6.0 now detects whether user is using your app or not. In the latter case it moves your app to idle mode. Differently than Doze maintenance windows are much more rare – approximately one per day. Heartbreaking? I know. But you have to live with it. Good thing is that your app isn’t idled without a reason – if the user doesn’t use it actively, why would you care about frequent syncs for her?

AlarmManager to the rescue

There are some cases when Doze/App Standby could cause some serious harm to user’s experience. Take the alarm clock app. You probably wouldn’t be satisfied with a longer battery life being late at the office just because your phone was in Doze at 7 AM. Fortunately, Marshmallow’s AlarmManager offers a way to bypass that behavior in special cases.

AlarmManager.setAndAllowWhileIdle( int type, long triggerAtMillis, PendingIntent operation); AlarmManager.setExactAndAllowWhileIdle( int type, long triggerAtMillis, PendingIntent operation);

Be aware that both these methods are available since API Level 23. There’s no AlarmManagerCompat in any of the support libraries, but it’s pretty straightforward to write a replacement on your own.

public class AlarmManagerCompat { @SuppressWarnings ( "NewApi" ) public void setAndAllowWhileIdle ( int type, long triggerAtMillis, PendingIntent operation) { if (isAtLeastMarshmallow()) { mAlarmManager.setAndAllowWhileIdle(type, triggerAtMillis, operation); } else { mAlarmManager.set(type, triggerAtMillis, operation); } } @SuppressWarnings ( "NewApi" ) public void setExactAndAllowWhileIdle ( int type, long triggerAtMillis, PendingIntent operation) { if (isAtLeastMarshmallow()) { mAlarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation); } else { mAlarmManager.setExact(type, triggerAtMillis, operation); } } }

These methods can come in handy if your application:

Uses reminder notifications, for instance of upcoming tasks or calendar events,

Offers the alarmclock functionality.

One important thing. The fact your PendingIntent will get executed doesn’t mean you’ll be able to perform network requests. You can’t rely on the Internet connection in services you start using the AlarmManager. AlarmManager’s new methods are okay for scheduling offline work, but they won’t do for periodic networking.

High-priority GCM messages

Some apps may require connection regardless of the device being in Doze. Take the Hangouts app as an example. It would be useless if it would need several hours to deliver an incoming message notification. Fortunately, GCM comes to the rescue here and you can send the so-called high-priority messages to wake up user’s device no matter if it’s in Doze, or if your app is idle. High-priority messaging is a new concept, introduced together with Marshmallow’s developer previews. Turning it on is just a matter of adding a priority field to your GCM payload. All the “legacy” messages will be considered as with a ‘normal’ priority and won’t be delivered outside of the maintenance windows.

Attention! Overuse of this behavior can lead to some serious battery draining. You shouldn’t use high-priority GCM messages for periodic syncs. Use them wisely – good use cases would be the instant messaging functionality or a networking job that results in displaying a foreground notification.

Be a good citizen

Your app isn’t the only app on your user’s device. And most likely – unless you’re Baby Instant Sleep* app – it’s not the most important app on your user’s device. Nobody likes the feeling of ‘15% battery remaining’ popup just a few hours after they were fully charged. Behave well and be a good citizen. Your users will be grateful.

* Forgive me this dadsjoke, but I’m a fresh father of twins, I had to.