Optimizing battery usage in mobile apps
Effective mobile apps protect the user’s battery by deferring work that does not help the person using the phone right now. Android can restrict background execution through Doze and App Standby, but poor scheduling still wakes the CPU, radios and sensors, drains the charge and can break trust.
Begin with measurements rather than blanket restrictions. Then pair WorkManager or JobScheduler with sensible data rules, network constraints and screen-aware design. The payoff is a longer charge, faster responses on intermittent connections and fewer surprise battery alerts.
Measure real battery drain
Use Android Studio’s profiler and adb shell dumpsys batterystats to compare a release build with a baseline. Look for long-running CPU work, wake locks, frequent network activity and alarms attributed to your package. A drain report is more useful when it identifies the user journey, such as opening a saved article, rather than blaming the app as a whole.
Repeat each scenario on a physical device, including one with background activity enabled and another with battery optimisation restricted. Record screen-on time separately from standby time, then check the battery history screen for the same period. If a tutorial example behaves differently on an Australian handset, send the model, Android version and reproducible steps to email the maintainers before changing the implementation.
Schedule work that can wait
Persistent, deferrable work belongs in WorkManager. Give it constraints such as connected network, charging or available storage, and use a unique work name so reconnects do not create duplicate sync jobs. Given a SyncWorker, constrained periodic work can be scheduled like this:
val request = PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
workManager.enqueueUniquePeriodicWork(
"content-sync",
ExistingPeriodicWorkPolicy.UPDATE,
request
)
Fifteen minutes is the minimum repeating interval here, and it is not an exact execution schedule. Choose a duration from the product’s freshness needs; frequent polling for changing content usually costs more than accepting slightly older data.
Resist while (true) timers and repeated Handler.postDelayed() calls. They keep waking the process without respecting Doze or App Standby. For user-initiated downloads, use a foreground service with a visible notification and release resources promptly. For exact alarms, use AlarmManager only when precise timing is essential and the required permissions and user authorisation apply.
Reduce radio, location and sensor wakeups
Mobile radios are expensive when they change state, so batch small requests into one response, reuse cached data and apply exponential backoff with jitter after failures. Compression helps transfer size, but fewer round trips often saves more energy. A news or shopping feed should refresh when connectivity returns rather than retrying continuously in a lift.
Request location only while the relevant screen or journey is active, use coarse precision where it meets the feature’s needs and stop updates when the user leaves. Apply the same discipline to Bluetooth scans, camera access and motion sensors: set a clear purpose and a timeout instead of leaving collection running indefinitely.
| Workload | Higher-cost pattern | Lighter approach |
|---|---|---|
| Remote content | Poll every few minutes | Batch updates with network constraints |
| Location | Continuous precise fixes | On-demand, coarse updates with timeouts |
| Preferences | Synchronous writes on every change | Asynchronous writes for non-critical values |
| Media playback | Hold wake locks while paused | Release locks promptly when appropriate |
In Australian cities, commuters often check transit updates on Sydney trains or Melbourne trams, where a fresh response matters. A useful compromise is a short foreground refresh followed by a deferred background refresh, not a permanent connection.
Keep screens and listeners quiet
UI work can drain power through repeated drawing, timers and screen wakeups. Avoid animation that continues after the screen is no longer visible, and respect the system animation settings rather than forcing long durations. In ListView or RecyclerView examples, reuse views, set stable IDs, keep item rendering lightweight and avoid starting a per-row polling loop that survives the activity.
Hold a wake lock only for the operation that needs it, apply a timeout and release it in a finally block. For SharedPreferences, use apply() for non-critical writes and reserve synchronous commit() for values that must be available immediately. These choices reduce blocking and make the behaviour easier to reproduce in tests.
Test power behaviour on real devices
Correctness tests do not prove that a feature is efficient. Extend the scenario with battery counters before and after, monitor wake locks and network requests, and repeat the journey with the display off. Android Studio’s Energy profiler and platform test tooling can expose regressions that ordinary unit tests miss. Macrobenchmark-style scenarios are especially useful for startup and scrolling regressions.
Try Samsung, Google Pixel and OPPO models sold in Australia, along with an older device still in everyday use. The structured scenario approach used in web testing guidance can inspire repeatable checks, but Android-specific measurements remain essential. Test a flight mode-to-network transition and a screen rotation, then compare the results with the profiler baseline.
Make energy checks part of the release routine
Treat power as a release criterion, not an optional refinement. Add battery checks to pull requests and watch Android vitals and support reports before widening the release. Australian development teams can use staged Google Play rollouts to compare battery-related feedback against a previous version before reaching more users.
- Set a measurable budget for wakeups, data transferred and background jobs during one representative user journey.
- Schedule sync around network and charging constraints, and cancel obsolete work when the user signs out.
- Require a profiler capture and a physical-device run for changes that add polling, location or sensor access.
- Test weak coverage and rapid network transitions, especially for regional NSW and other areas with patchy mobile service.
- Keep customer wording in mind: Australians may call an empty battery “flat”, so support tags should capture that alongside “battery drain”.
A durable optimisation removes unnecessary wakeups while preserving the features people rely on. That balance produces apps suited to long Australian commutes, regional travel and everyday use, where reliable performance matters more than unnecessary background activity.