If you can measure power drain well yourself, that is the best way for you to determine precisely where your power consumption is going. Alas, for various reasons, you may not be able to get good power consumption data.
Which means you may have to guess.
We know the general sorts of things that consume power in a device, such as the screen and the CPU. We know that if we use these things less, we will use less power. Eventually, though, we have an app that does nothing, and while this may result in optimal power usage, we are still likely to get poor reviews, because the app does nothing.
What we need is some rough idea of how bad certain things are, so we can weigh our use of those system components appropriately.
This chapter will try to give you some “rule of thumb” heuristics of how to estimate power usage of various system components, plus some general recommendations of how to use less of that particular component without necessarily eliminating useful functionality from your app.
Understanding this chapter requires that you have read the core chapters and understand how Android apps are set up and operate.
Also note that:
Screen size and battery size generally trend together. Tablets have bigger batteries and bigger screens than do phones, which in turn are bigger in both areas than are wearables.
A rough rule of thumb is to expect to consume ~10% of the device’s battery for every hour you keep the screen on. Or, to look at it another way, on a phone-sized screen, expect a power draw of ~100-200mA, depending on variations in screen size and display technology (e.g., AMOLED).
Normally, the user is in control over how long your app is in the foreground and therefore is “to blame” for the screen being on. There are a couple of cases where you can make the screen be more of a problem.
The first is if you acquire()
a WakeLock
(other than a PARTIAL_WAKE_LOCK
)…
and forget to ever release()
it. Since the WakeLock
will keep the screen on,
the screen will stay on, even if your app is in the background, until such time
as your process is terminated or the device shuts down due to low battery.
In fact, such WakeLock
types have been deprecated, with the last of them
being flagged as deprecated in API Level 17. The recommended alternative is
to use android:keepScreenOn
or setKeepScreenOn()
on some View
. This
will keep the screen on, so long as the activity hosting that View
is
in the foreground. That way, just moving to the background releases the underlying
WakeLock
, allowing the device to return to sleep.
However, in some cases, even that may be insufficient. Suppose that the
user is in your activity, and they get distracted, putting down their device
for an extended period. Unless you somehow detect the inactivity, and manually
turn off the keep-screen-on mode, the screen will stay on indefinitely, until the
power is drained. Hence, if you have a decent way of determining if the user is
still using your activity, consider using that as a way to determine when
the device is inactive (e.g., a postDelayed()
that gets canceled and rescheduled
when the user does something, so if the postDelayed()
Runnable
gets invoked,
you know the user has done nothing for the delay period). Then, if you know the
device is inactive, call setKeepScreenOn(false)
to return the screen to its
normal operating mode.
The academic paper “How is Energy Consumed in Smartphone Display Applications?” has a more extended analysis of screen power draw.
Disk I/O gets more efficient with bigger operations.
You can see this in something like SQLite, where wrapping a bunch of INSERT
statements into a single transaction can have substantial benefits in terms
of how long the I/O takes.
Not surprisingly, this has a similar impact on power consumption:
Hence, you want to try to batch up your disk I/O, where possible, to do fewer, bigger operations, rather than lots of little ones. This includes:
BufferedInputStream
and
BufferedOutputStream
, if you can afford the heap space, though the 8KB
defaults are not that badAs a rough model, consider disk I/O to draw ~200mA. The smaller the I/O operations, the more time it takes you to accomplish the work, and hence the less efficient those operations are.
While disk I/O is relatively expensive while it is occurring, most apps are not continuously reading or writing, and therefore the total impact to the battery will not be that bad. Apps that do continuously use the disk — such as music or video players — will consume quite a bit of power.
Internet access via WiFi and mobile data networks is another area that you, the developer, tend to control. Some apps require continuous Internet access and only while in the foreground, like a streaming media player. But many more apps wind up doing Internet access periodically in the background, looking for new information on some server somewhere. Unfortunately, these are the sorts of “vampire” apps that can drain the battery without users necessarily being aware of it. Individually, these apps might not even appear all that bad, but when a device has dozens of them, the combined impact results in poor battery life.
Moreover, we also have the problem of dealing with multiple ways of getting to
the Internet. Simple solutions will leave us totally oblivious to the differences
in downloading via WiFi versus mobile data, at the potential cost in battery
consumption. Slightly less-simple solutions optimize for mobile data, to try
to minimize power drain in that model. More-elaborate solutions detect what
sort of connection we have (using ConnectivityManager
) and choose among
different strategies as connectivity changes.
Here are some things you can do to try to help manage your Internet power consumption.
The simplest, rough-cut way to consume less power for Internet access is to do less Internet access in the first place. The less time you spend downloading (or uploading) data, the less power you tend to draw while doing so. In a very coarse approximation, battery consumption will be proportional to bandwidth consumption.
And, of course, consuming less bandwidth can have other benefits, particularly for people on metered mobile data plans.
There are chapters elsewhere in the book that cover ways to deal with bandwidth consumption for bandwidth’s sake.
For data that is likely to be unchanging, use a disk cache, so you can avoid downloading the same content again. Such a cache can be used at two levels:
If-Modified-Since
and
ETag
headers), you can make a request to the server to download the content
again, where the server can tell you if you already have the current copy
of the content (via a 304
response code).Many of the Internet libraries discussed earlier in this book offer disk caching as part of their services.
As noted earlier in this section, in a very coarse approximation, battery consumption will be proportional to bandwidth consumption.
Unfortunately, that approximation is pretty coarse.
We as developers tend to think of Internet access as being like a faucet with two states: on and off. In reality, wireless radios tend to have three states: full power, low power, and standby mode. Opening a socket will bring the radio to full power. An idle radio (no packets transferred) will drop to low power after a while, and eventually back to standby mode. Not surprisingly, the power draw for full power is substantially more than low power, which in turn is more than standby.
However, this model introduces some problems:
The net is that you want to bring the radio to full power as few times as possible (to minimize the percentage of time we are slowly dropping back to standby and consuming power while we do). And, while we are at full power, we want to do all necessary — or perhaps possibly necessary — data transfers, to avoid having to go back to full power again any time soon.
In other words, you want to batch your network I/O. This is reminiscent of the recommendations to batch disk I/O from earlier in this chapter.
So, for example, if you are going to upload data to a server, use that same pulse of work to download anything that needs downloading, rather than having separate schedules for uploads and downloads. Doing more in a batch and having fewer batches will reduce the cost of the power state changes.
One common pattern for Internet access is to poll a server. This is fairly easy
to code, using something like AlarmManager
to get control every so often.
However, this approach resembles children in the back seat of a car, frequently pestering their parents with “Are we there yet?”.
Just as the parents will tell the children “We will get there when we get there, and we will tell you when we get there”, you can take a similar approach, using Google Cloud Messaging (GCM). Rather than poll the server periodically, have the server contact your app on the device when there is data ready to be downloaded. This works well in cases where polls are likely to result in “yes, we have no data” responses — the pushes can be far less frequent than the polls would be. This can also reduce load on your servers, for not having to respond to poll requests across all your users.
Note, though, that the battery benefits are from using GCM itself. From the standpoint of an app, GCM is “always on”, and the power consumed by GCM is attributed to Android itself, not to the app. Hence, pushes are almost “free” from the standpoint of power cost. This will not be the case if you “roll your own” push system (MQTT, WebSockets, etc.). In this case, you are attempting to keep a long-lived socket yourself, in addition to the one maintained by GCM. Clearly, there are ways to do this that minimize the power consumption of the long-lived socket connection, but that is not easy to accomplish. Hence, you need to weigh the costs of depending upon the Play Services SDK and routing your communications through Google’s servers with the costs of trying to do your own separate push mechanism in a battery-friendly fashion.
If server push through GCM is impractical (e.g., you do not control the server), you can reduce your power use for Internet access by batching across apps, in addition to batching within your app.
What Google wants you to use for synchronizing data with a server is the
SyncManager
. This is an overly-complicated framework that, among other things,
gives you control to sync to the server at the same time that other apps needing
to sync get control. That way, we can “warm up” the wireless radio once and
handle several apps’ worth of data transfers at once. SyncManager
will be
covered in this book eventually.
Part of the reason why Android moved to make alarms with AlarmManager
more “inexact” in API Level 19+ is for this same sort of batching. While
AlarmManager
certainly can be used for a variety of purposes, a lot of apps
use it for Internet data transfer. Allowing Android to control when those
alarms occur allows Android to try to coalesce them, and perhaps even time them
to happen when SyncManager
-led transfers occur, with the objective of minimizing
the number of times we bring the wireless radio out of standby mode.
The Android developer documentation has a series of “training” pages on minimizing power consumption for data transfers. This expands upon Reto Meier’s Google I|O presentations that touch upon this topic.
In light testing, GPS seems to draw ~35mA. Additional power will be consumed for using those results, though, and so the net effect on the battery will be somewhat higher, depending upon what your app does when it gets a GPS fix.
That figure is corroborated by the academic paper “An Analysis of Power Consumption in a Smartphone”, though that paper tested rather old devices (HTC Dream and Nexus One).
Again, different devices will have different components, and some devices’ GPS modules may be more or less efficient.
Hence, GPS itself is a power drain, but not a massive one… if what you are doing with the GPS fixes itself is efficient. Keeping the GPS on for several hours will certainly take a chunk out of the battery charge, but if you are doing lots of work (e.g., navigation app) in response to those fixes, several hours may be more than the battery can handle.
If you can get by with the dependency on the Play Services SDK,
using LocationClient
can help here, particularly in cases
where the user may not be moving much, as Google’s fused location provider uses
the accelerometer to help determine how much they need to use GPS versus other
possible means of determining location.
The camera will consume power while it is actively receiving input, whether that is for the preview frames or for taking full-resolution pictures or video. Of course, it will also consume additional power when recording images to disk, whether those be still photos or continuous video.
A rough guide is that a camera preview will draw ~200mA plus the power for screen, CPU, etc. That could easily total over 350mA, even if you are not doing much. Normally, though, the camera preview is on for short periods of time, and only under user control.
A corresponding value for recording video, including the disk I/O and camera preview, would be ~600mA (plus the screen). That is the sort of thing you only want to do in short bursts, as a couple of hours of video recording can really take a bite out of battery. However, once again, normally the user is the one controlling when video is recorded.
The above sources of power drain are comparatively easy to model and provide a heuristic for determining your possible power usage.
However, there are plenty of other things that can drain the battery, for which this chapter does not provide such a heuristic. In many cases, the usage patterns of the system component will vary so widely that a simple heuristic is unrealistic. In some cases, the power drain from components from different manufacturers will be very different. In some cases, the author of this book simply lacks sufficient expertise with the technology to provide much help (e.g., Bluetooth).
The sections that follow will try to provide some help, though.
Perhaps the biggest source of power drain beyond the components listed above will be the processors: the CPU and the GPU. These draw a fair bit of power, which is why processor manufacturers go to great lengths to try to adapt to varying conditions, turning off cores or switching clock speeds, to try to minimize the power drain.
Usually, so long as we are in the foreground, any CPU/GPU usage impact on power will be considered “normal” by the user. Of course, trying to boost performance here can benefit the user, not only in terms of possibly reduced power consumption, but less lag or other forms of sluggishness. Hence, trying to optimize processor utilization is worthwhile.
However, the bigger complaints from the user will come from power drain while
your app is in the background. The biggest source of those complaints will
come from your use of WakeLock
s, preventing the device from going into a low-power
sleep state.
There are some apps available on the Play Store that reportedly can give you some
idea of how long you may be holding a WakeLock
, however they generally require
root, particularly for Android 4.4+.
Sensors, more so than many other device components, seem to get sourced from a wide range of manufacturers. They also seem to be tied into the devices differently from device to device. For example, some devices allow sensors to continue collecting data while the device is otherwise in a sleep mode, while many do not.
As such, it is difficult to give much guidance in terms of power drain tied to your use of sensors.
That being said, here are a few notes that may help:
Playing audio through the earpiece, speaker, wired headset, or Bluetooth, will consume some amount of power. The amount will vary by how long you are playing the audio and how the audio is played (e.g., Bluetooth may require more power than on-device audio output). However, in both cases, usually the user has control over the audio, particularly if it is to be playing for a lengthy period of time (e.g., music player), and so the power drain associated with audio playback is less likely to be considered to be a problem, as users will get annoyed with uncontrolled power drain, more so than power drain that they can manage themselves.
Recording audio via the on-board microphone or Bluetooth should also consume some incremental power. In cases where the user is in control over when recording is happening, the power drain is unlikely to cause the user much distress.
Where both playback and recording of audio may cause a perceived power problem is in places where the user has less control. For example, an alarm clock app should have some sort of timeout to stop playing the ringtone (or whatever) after some period, if the user fails to respond to the alarm. After all, it is possible that the user is not where the device is and is not in position to stop the alarm. In this case, the power drain will be from several components, audio playback being just one, but it is the uncontrolled nature of the power drain that can get you in trouble.