Doing Periodic Work

Another Android Headache

Apple and Android

In the Beginning

  • iOS: Environment tightly controlled, no background work possible
  • Android: Freedom! Background work possible, endorsed, encouraged

Scenarios for Periodic Work

  • In the UI (e.g., remaining-time counter)
  • In a running service
  • Independent of a running app (e.g., server sync)

Periodic UI Updates

Use postDelayed()

  • Cheap: no background threads required
  • Easy: you get control on the main application thread

An Already-Running Service

Use ScheduledExecutorService

  • Part of the java.util.concurrent package, not Android-specific
  • Fixed-rate and fixed-delay options

Options for Independent Periodic Work

  • The everlasting Service, coupled with the preceding technique ...THIS IS TEH EVILZ
  • AlarmManager
    • setAlarmClock()
    • Other set...() methods
  • JobScheduler
  • GcmNetworkManager (quasi-backport of JobScheduler, requires Play Services)

AlarmManager Options

  • Wake Up, or Not?
  • Repeating, or Not?
  • Inexact, or Not?
  • Absolute Time, or Not?
  • What Happens

AlarmManager Alarm Types

  • RTC
  • RTC_WAKEUP
  • ELAPSED_REALTIME
  • ELAPSED_REALTIME_WAKEUP

AlarmManager: Original Recipe

  • Get an AlarmManager via getSystemService()
  • Create a PendingIntent to indicate what should happen
  • Configure alarm using AlarmManager
    • set()
    • setRepeating()
    • setInexactRepeating()

AlarmManager: API 19 Style

  • Get an AlarmManager via getSystemService()
  • Create a PendingIntent to indicate what should happen
  • Configure alarm using AlarmManager
    • setExact()
    • set() and setWindow()
    • setInexactRepeating()

AlarmManager: Twenty-Something

  • API 22: cannot have a period under one minute (undocumented)
  • API 23
    • Doze mode/app standby
    • set...AndAllowWhileIdle()

JobScheduler

Smarter Than Your Average AlarmManager

  • Intrinsically inexact
  • Criteria along with time
    • Are we on a charger?
    • Do we have an Internet connection? How about WiFi?
    • Is the device "idle"?
  • WakeLock managed for you

JobScheduler on Android N'Oreo

Content Monitoring

  • Register a Uri
  • Have a job invoked when that content changes
  • Like a ContentObserver, minus the everlasting service bit
  • Example: watching for changes in contacts

Doze Mode

  • Device has not moved and is not charging for 1+ hours
  • Background processing becomes infrequent ...as in "once every few hours"

App Standby

  • Device is not charging
  • User has not been in your app for quite some time
    • No activities
    • No foreground service or other notification
  • Background processing becomes infrequent ...as in "once every day"

Specific Impacts

  • No AlarmManager alarms
  • No JobScheduler jobs
  • No SyncManager syncs
  • Outstanding partial WakeLocks ignored

Workarounds

  • User whitelist in Settings ...just don't try asking the user to do it
  • AlarmManager Options
    • setAndAllowWhileIdle() and setExactAndAllowWhileIdle()
    • Give you control every ~15 minutes
    • Seemed unreliable in testing
  • GCM ...which doesn't work if the device is offline, and requires Play Services

Doze and Android Notsurebutitsprobablytasty

Semi-Doze Mode

  • Device is moving, but screen is off
  • Outstanding WakeLocks are honored, as is AlarmManager
  • Otherwise, dozing

Why?

I need to send a message to the server... once a minute... for 2-3 hours. To achieve this I am currently using AsyncTasks (for sending the request), launched once a minute via a foreground Service, which is scheduled with alarmManagers' setExactAndAllowWhileIdle. The foreground service does have a partial wakelock too!
(posted April 7, 2016)

This Is Why We Can't Have Nice Things

Special Snowflake Syndrome

  • Too many developers being wasteful with the battery
  • Too few developers honored the API 19 nudges
  • Too many users complaining about horrible battery life

So, Now What?

  • Design and Market for Unreliability
    • Tout: manual refresh options
    • Downplay: automatic refresh
    • Don't offer: priority alerts
  • Use GCM... if you can live with the limitations
  • Lean towards JobScheduler, if your app is for API Level 21+
  • Cry in your beer

Apple and Android

Opposites Attract

  • iOS: Environment tightly controlled... but now we have hooks for background work
  • Android: Freedom! Just, not as much!