App battery drain is the worst. There are few things more inconvenient than a dead battery—especially when you need it most. We’ve all been there. Indeed, as a consumer, I notice when applications take up more than their fair share of battery life. You can be sure that your customers notice, too.
According to Statista, mobile users keep as little as 3% of the applications they download. Among the biggest reasons users cite for uninstalling an app is battery drain. It’s easy to understand why an app’s battery optimization is intrinsically tied to its user experience.
Operating in a highly competitive app ecosystem, mobile app developers increasingly find themselves challenged to build world-class, high-quality applications while, at the same time, saving battery life. In turn, there’s never been better time to consider a few methods you can use to prevent your app from being, well, a drain.
Optimizing launch sequence
Is your application optimized for launch? If not, it should be—after all, launch is typically one of the most energy-draining events in an app’s use cycle. When a user launches a mobile app, that app must rely more heavily on device RAM to load components, connect to a network, recall cached memory and settings, and load and arrange its UI.
Wise developers take the time to develop an well-considered launch sequence that saves battery while also providing users with quick access to functionality. Remember, apps feature multiple ‘start states’. Not all app launches are created equal, and there’s a significant difference between opening an app after your phone powers down and resuming an app after checking your email or locking your device.
Consider the following app startup states:
This state occurs after a user reboots a device, specifically when a user uses the app for the first time since reboot. Cold starts use the most energy and are also where most performance issues occur.
Warm starts feature similarities to cold starts but occur when the user closes an app and reopens it while some application processes are still running in the background.
Hot starts make for the quickest and least resource-intensive status state. This state brings activity to the foreground, while most processes are still running in memory.
Decreasing the load
In each case, the goal is to decrease the load placed on the app during startup, which will in turn increase performance, improve user experience, and improve battery efficiency. Some common solutions include:
Lazy initialization involves delaying initialization so that only necessary items are loaded during start-up, while less critical functionality is delayed or occurs during different events. Think about your app lifecycle and processes and ask yourself, can anything be deferred? Can anything be batched together or can anything be combined? You may be making redundant steps, and eliminating redundancy is always the first step toward achieving efficiency.
Execute resource intense code on separate threads
Certain operations, like network and disk operations, should be run on a different thread than the application.onCreate(). This prevents bottlenecks. Seek out and eliminating bottlenecks is another important step toward increasing efficiency.
Some operations depend on others, while some can run independently. Ensure that you sequence your initialization well and that you’re not inadvertently creating locks. Remember—efficiency!
Optimize background operations
Background work is when no app activities are visible to the user or if the app is not running any foreground services.
Execution limits and background processes
To the annoyance of app developers (yet to the benefit of battery life), both Android and iOS maintain background execution limits. These limits conform app developers to standards when running apps in the background. Android OS will prompt a user to restrict app actions for resource-intensive applications.
Events that may result in a restricted access prompt include excessive wake-locks. This occurs when the user needs to power down the screen, but the application prevents them from doing so. Apps do this so that a process can finish or due to excessive background services. You can further conserve battery life by paying attention to how you manage background processes.
WorkManager is an Android JetPack Library that helps you manage deferrable long-running background tasks. This handles threading, ensuring execution on the background thread. It also makes it easy to schedule, cancel, and query tasks. It can do all of this while guaranteeing there is enough bandwidth to make sure processes that start also complete successfully. iOS developers using Flutter can also take advantage of WorkManager through an iOS wrapper (see this article from some recent discussion from yours truly on Flutter).
Background work can be immediate, meaning it must run right away, be long-running, or be deferrable. In addition, background work can be thought of as persistent or impersistent. Persistent meaning that the work is continually scheduled to be done (like calling an external service for new data). Impersistent is work that does not need to be scheduled again after it completes once.
In general, it’s a good idea to send all persistent work to the background with WorkManager as well as long-running, deferrable, and impersistent tasks.
Monitor connectivity and docking state
As you’re aware, you’re not always going to be able to connect to the internet when you want to. An app running a process that requires connectivity will use considerably more resources if relying on data, instead of secure and stable WiFi. Developers can check the connectivity state before running processes. Based on connectivity status, you can resume, start, or cancel background tasks. With Android development, use ConnectivityManager and with iOS, use Reachability to monitor the connection broadcast.
The docking state determines if you’re connected to a charging source and what kind of charging source the device is using. For example, if you’re connected to a car dock, you’d want to regularly update background traffic service alerts while also avoiding or limiting these alerts to save battery if not docked. When docking states change, you can optimize, and reorganize background processes to accommodate the new state. Both iOS and Android allow you to check the dock state.
How do you know if your app is consuming too much battery? That’s an important question to answer when trying to optimize battery life. It’s much better for you to discover that your app has a battery problem before your customers do. Fortunately, there are a few tools that identify and track certain battery measurements.
For Android devices, Battery Historian allows you to analyze power usage over time. With Battery Historian, you can view at either the system or app level. From the app level view, you can analyze network information, process information, and examine services. Battery Historian will provide estimated battery life for your app and compare it to other apps in your system. In addition, it will break down battery usage by process so you know where battery issues are and where optimizations can be made.
For iOS, the Battery Usage tab in Xcode displays battery usage broken down by foreground and background power usage. Analyze battery usage over a 24-hour period for both on-screen use and background use. Power usage is further broken down into ‘Power Categories’ like network, processing, camera, Bluetooth, and location.
Beyond app battery drain
App battery drain is a big issue. But in today’s mobile app testing landscape, creating a blockbuster app is nothing short of challenging. There are likely hundreds of options just like yours. Customers are more discerning than ever. Any app that doesn’t add value, simply has to go! There are few things more corrosive to user adoption than poor battery usage. No one likes an energy zapper. By focusing on battery consumption during app development, and continually monitoring for optimization, you can ensure your app is adding value, not draining battery.
Disclaimer: The views and opinions expressed above are those of the contributor and do not necessarily represent or reflect the official beliefs or positions of Sofy.