When developing your tailor-made Android app we need to make sure that the app uses as little battery power as possible, starts up quickly and responds quickly and gracefully to user swipes and clicks. Nobody wants to use a sluggish app or one that drains the battery!
Processes and Threads
When the custom-made Android app we've developed for is started on your device, the Android operating system starts a new Linux process for the app with one "main" thread.
Processes
The default setting for the Android operating system is that all components of an Android app run in the same process. We do have the ability to change this in the app's manifest file so certain activities, services or broadcast receivers run in their own process (using the android:process attribute), however, we generally code our bespoke Android apps to use the default one-process model.
The process lifespan cannot be controlled by the custom-made Android app we've developed but is instead controlled by the Android operating system on the device which can kill processes if it needs to free up memory so we need to make sure important processes are in the foreground so the operating system knows they are running and therefore prioritises keeping them open over and above other conflicting demands for resources.
Our Android app development team pays particular attention to the interaction between activities, services and broadcast receivers to avoid the risk of the Android operating system killing the process before it has finished some mission-critical task.
Threads
As mentioned above, your app runs under the "main" thread which is generally the thread that deals with all UI activities (i.e. the User Interface screens you see when using the app). When the Android apps we develop need to carry out intensive tasks following say a user selection or button click, then this single thread model can give less than optimum performance (leading to screens 'hanging' or 'freezing' because the UI is blocked until such tasks have finished).
We have two basic rules when it comes to coding our bespoke Android apps:
1. Never block the main UI thread with intensive tasks.
2. Never access the UI from outside the main UI thread.
Background Threads
It is absolutely imperative that we do not block the main (UI) thread when performing resource-intensive tasks (like syncing data, photos or videos with the cloud) as otherwise our Android app could hang or freeze, and therefore we carry out these tasks on separate background threads. However, as we cannot update the UI (e.g. the app screen you see) from any thread apart from the "main" thread, the Android operating system gives us some 'Runnable' methods we can use to access/update the UI from a background thread.
Activity.runOnUiThread(Runnable)
This Android method executes the specified action on the main UI thread.
View.post(Runnable)
This Android method causes the Runnable to be added to the main UI thread's message queue.
View.postDelayed(Runnable, long)
This Android method causes the Runnable to be added to the main UI thread's message queue but to be run only after the amount of time set in the 'long' value has elapsed.
However, the aforementioned 'Runnable' methods to access the main UI thread from background threads become difficult to maintain (having to manage threads and handlers) and therefore in the bespoke Android apps we develop for clients we tend to always use the AsyncTask class for short background tasks (i.e. those taking no more than 5 seconds). If we need to keep background threads running for a long time due to some long-running operation, we can use dedicated Java APIs for long running thread tasks such as Executor.
AsyncTask
The AsyncTask class allows our Android app developers to carry out short background tasks and then publish the results on the main UI thread without having to mess around with handlers.
Executor
This Java interface executes submitted Runnable tasks without our Android app developers having to know how each task will be run (e.g. thread use and scheduling).
Optimising our Android apps to conserve battery life
Nobody will want to use one of our custom-made Android apps out in the field (e.g. a travelling sales rep or engineer) if the app drains the battery before the day is out. Therefore making sure the Android apps we develop do not use battery power unnecessarily is of the utmost importance to us. We do this by using Android operating system features to manage an app's battery consumption as well as using tools during the testing phase of our Android app's development to identify any tasks which may be draining the battery. We will ask the client important questions during the discovery phase of their app's development, e.g. do they need data sent up to the cloud instantly or perhaps only when the device is charging. As syncing data with the cloud can be a big drain on the battery, it is always worth asking this question (although in our experience most clients want their field worker's data synced with their cloud based systems as soon as possible).
Our Android app developers have found that the best way to conserve the battery life of a device on which one of our bespoke Android apps is installed is to schedule jobs intelligently. These jobs are mainly to do with updating data from/to the cloud and updating background tasks. There are several Android APIs that our bespoke Android apps can use to schedule background work, however, the recommended option is currently the JobScheduler class which offers our Android app development team very scalable functionality and is suitable for large tasks such as syncing a database to the cloud.
Because the latest versions of Android aggressively restrict apps which hog system resources (e.g. memory or battery), e.g. they may block Location services when the screen is off so you cannot get the user’s current location or they may block Internet access to apps in the background which could stop data cloud syncing, we therefore try to test your app while battery saver is active to make sure everything works as it should when the operating system decides to restrict certain features when the app is not actively being used at that moment. Useful hint: you can turn on the battery saver manually through the device's Settings > Battery Saver screen.
There are also Android tools such as ‘Profile GPU Rendering’ and ‘Battery Historian’ to help our Android app developers to identify areas that they can optimise for an improved battery life.
Profile GPU Rendering
The Profile GPU Rendering tool tells us how long it takes to render the frames of an app screen (using a benchmark of 16ms per frame) which tells us if the GPU is getting overloaded when trying to render (draw) complex graphics etc. on the Android app screen.
Battery Historian
Battery Historian is a tool that allows developers to inspect app-specific battery use info while the Android device was not on charge.
Restricting an Android app's use of memory
Mobile devices usually have limited memory (RAM) so coding our Android apps to use the least possible memory (and release any allocated memory as soon as no longer needed) is very important. Fortunately for Android app developers, both the Android Runtime (ART) and Dalvik virtual machine keep track of memory allocation and carry out routine garbage collection (a mechanism for reclaiming unused memory).
The Android operating system sets a hard memory limit for each app depending on how much RAM in on the device and if our app reaches that limit it can trigger an out-of-memory error. Fortunately we can code our Android apps to interrogate the operating system (by calling the aptly named getMemory class) to see how many megabytes of data we have available in case we wish to cache a lot of data between screen loads rather than say writing to the SQLite database and reading back on the next screen load.