Regular readers of Styling Android will understand that it is dedicated to improving the look & feel (UI) and User Experience (UX) of Android apps. One particular area in which we can really frustrate our users is when the app does not respond to their touches / clicks, and it is vital that we keep our app as responsive as possible. I use the term responsive in the context of responding to the user’s actions and not as it is often used in the phrase “Responsive Web Design” to describe how your presentation adjusts to the display. In this series of articles we’ll have a look at some useful techniques for keeping your apps responsive.
Android is a multi-threaded environment, and the common Java threading components are available to us. When an Android app is launched, the system creates a thread for the application which is known as the “main” thread. There are some others created as well, but the key one is “main”. If you run up any project under the debugger in Eclipse you will see the main thread:
The main thread is really important because it is the thread which handles UI events. When the user touches the screen, any touch / click handlers that we have registered will be invoked on the main thread. This is why often the main thread is also referred to as the “UI thread”. Personally I prefer the term UI thread because it acts as a constant reminder that it is handling UI events.
Android uses this one thread to handle all UI events, and if our app performs a long running task on the UI thread, subsequent UI events will not be handled until this task completes. To the user this will appear as though the app has hung. Android does provide the user with protection against badly behaving apps. If your app ties up the UI thread for more than 5 seconds (or a BroadcastReceiver does not complete within 10 seconds), Android will throw up the dreaded “Application Not Responding” (ANR) dialog which gives the user the opportunity to quit your app. I cannot stress enough how bad this is to the user, and is highly likely to get your app uninstalled!
So the very simple key to keeping the UI responsive is to keep the UI thread as free as possible. Whenever we respond to UI events we must complete as quickly as possible. If we have something non-trivial to do, then we need to consider doing it on another thread so that we can free up the UI thread as quickly as possible.
A really important thing to remember is that all of the life-cycle methods of our Activities are executed on the UI thread. So we should not be performing, for example, network calls in the onCreate() method of our Activity.
One of the problems that we face is that sometimes we cannot be sure when a heavy method will be invoked on the UI thread. Fortunately we have StrictMode which was introduced in Gingerbread (API level 9) and will alert us to potential problems. I’m not going to provide a full tutorial on StrictMode here, as it is really quite straightforward. I would advocate enabling StrictMode during all testing to help identify all potential problems. Always remember to remove it before releasing you app, though!
Hopefully you should understand why it is important to keep the UI thread as free as possible. In the next part of this series we’ll begin looking at techniques to enable us to do this.
© 2012, Mark Allison. All rights reserved.
Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.
Looking forward to the nuts and bolts articles coming up!
Although potentially not directly related, I’d like to see an implementation that saves data through orientation changes.
Our apps are not guilty of doing anything big in the UI thread, but we are guilty of not storing the information through a rotation change. So that the background network work has to go all over again for a rotation change.
I’ll put rotation change handling on my articles todo list. It may be a few weeks before I get to it as there’s a few articles to come in this series first!
Activity::getLastNonConfigurationInstance() is way to go with non-parcelable resources.