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!