Have you ever woken up to a phone that looked like a toasted marshmallow? I’m hoping the answer to that question is no. But, you’ve probably experienced an overly warm Android in a less extreme way. Phones heat up when they’re working hard and hungry for power. And, that’s not a good thing unless maybe you actually want to use it to toast marshmallows.
As developers, we have a responsibility to our users. They don’t expect us to abuse their battery life — nor should they. We must own up to that responsibility by doing our due diligence to ensure our apps are running cool. If your app is a hot potato burning through your users’ precious battery life, you won’t be able to hide it.
A great Play Store rating is marketing gold, and a bad one can sink the ship. Users are demanding, and they won’t hesitate to make their voices heard through 1-star ratings. Don’t let excessive battery drain contribute to those. Take a good look at your code and ask yourself these simple questions:
Do I really need to make all those network requests?
It’s OK to be a scrooge when it comes to downloads. Look closely at your data providers (web services, etc.) to see if you can batch download data. For example, instead of making 10 requests to download 10 things, try to make one request that returns all 10 in one response.
As web serviced apps get more complex, in particular contexts, dependencies on several HTTP API endpoints will likely surface. With some great UX design and clever coding, that can be perfectly fine as long as performance and battery life aren’t adversely affected. In some cases, though, even the cleverest of solutions may be inadequate. You might find that you need to reduce the number of round trips to ease up on the power hungry mobile radio.
If you control the API, you could redesign the problematic segment of the API to better suit your use-cases. If you don’t control the API(s) or perhaps your web service is built on several microservices, you could build a proxy that sits in front of the API(s) such that your app makes one network request to the proxy, the proxy makes many, consolidates the data, and sends it all back to the app. Other emerging methodologies like BFF and GraphQL are efforts that can reduce round trips and are worth considering too.
Images can be large, and therefore costly. When downloading images, only download the ones that are immediately visible (or highly likely to be visible) on screen. If your content is in a ListView and the user flings to scroll, for example, don’t download images until the list loses a good amount of inertia because the user, unless they have Quicksilver-like superpowers, won’t be able to clearly see the speedily bypassing images, anyway.
Consider how you handle sending data as well. Don’t upload, for instance, location data, on every change event if you can avoid it. Queue data up, and upload it at some interval or threshold.
Am I making redundant network requests?
Cache is king. Utilize one, where possible. Treat bytes like $$$ and save them up. Use a refresh mechanism, cache items up to some limit, and let older items roll off the cache. To conserve memory and disk space, scale images down according to view dimensions or screen resolution and cache those too. Your cache doesn’t have to be a fancy SQLiteDatabase. A simple directory of files named by hashed URLs will usually do. Or, even better, use one of the many third party libraries out there, as caching isn’t a new solution.
Do I really need to download all that data?
If your data provider is feeding you data that you don’t really need, see if the provider’s API allows you to specify what data you want. For example, if each item in a list displays a title and description, that’s all the information that’s needed. So, in that case, downloading data in excess of those two properties is wasteful. Be conservative. Your users will thank you for being kind to their data plans, as well as their wallets.
When am I downloading data?
As tempting as it may be, don’t download data when your app is in the background just because Android let’s you. Resources aren’t infinite, unfortunately. Only download as much data as you need to provide a great user experience and prefetch data that makes sense.
In any type of scrolling view, for example, to have that extra little bit for the user to look at while you download more, we may download 10 items even though only a maximum of five can display on screen at a time. Then, you might start to download the next 10 after the user scrolls into the 6th or 7th item. Use caution, and don’t download in excess of what a user is likely to need in a given context. Find the right balance.
Can I make better use of an active radio?
Mobile radios are a lot like humans — they consume a large amount of energy waking up. Thus, it makes sense to time network requests so that you take advantage of the radio while it’s awake.
Let’s say your app absolutely needs to download data while in the background. It’s very likely that a user will have other apps installed that do the same. Luckily, the clever people on the Android team have provided APIs that allow background tasks to be scheduled in a loose manner such that tasks across many apps will run at the same time to take advantage of the active radio. For example, AlarmManager provides the setInexactRepeating method to facilitate opportunistic scheduling. That’s the old school way, and it’ll work, but there are newer APIs worth looking into such as JobScheduler that offer more flexibility.
Do I need to poll for data?
Maybe you do, but you probably don’t. Definitely consider Google Cloud Messaging instead. While you could poll for new data every n seconds or minutes or whatever, a better way would be for your data provider to notify you so that you can refresh your app only when necessary.
This is one of the key benefits of push notifications and where GCM can help. If you can’t avoid polling, add user configurable options for refresh frequency enabling your users to balance data freshness, bandwidth consumption, and battery life.
Be Good For Goodness Sake
The moral of the story is to be a good Android citizen. Be considerate, code smart, and conserve your users’ battery life. Coding smarter is not only good for your users and ratings, but it’s also really satisfying to build something that’s super efficient. The best developers know that it’s the small details — like battery life optimization— that make the difference between something good and something great.