We'll respond shortly.
We do a lot of Android software development at Xtreme Labs. Every two months we have a retrospective meeting to look back and reflect on the exciting discoveries, petty frustrations, and disseminate our findings to the group. There are some lessons that we’ve learned time and time again.
Have you ever seen an application hang and stop responding to your input? Did the animations stop sparkling? Did you see the dreaded Application Not Responding dialog box? These little emergencies can occur if you block your application’s UI-thread for too long.
Every application begins with one thread running a message loop. Everything that the user sees and all feedback they receive depends on the message loop. All of those Activity onResume, button OnClick, and all drawing events depend on that same message loop. If anything running on that thread takes too long, the user can experience a jarring episode of jankiness.
In particular, any operation that makes network requests or accesses the device’s filesystem can take precious time away from this message loop. If you make a network request and it takes more than a few seconds to return, then the user will see the Application Not Responding dialog box. A lot of users can’t tell the difference between these kinds of hangs and mundane crashes and will think your application is buggy (which, for all intents and purposes, it is).
This sin is so grievous that applications targetting the Honeycomb API, or greater, will experience NetworkOnMainThreadException if the application makes a network request using the UI-thread.
How do you guard against these misdeeds? Use AsyncTasks and ThreadPoolExecutors to toss your blocking calls onto worker threads. When your background tasks complete you can use callbacks or post messages to your UI-thread’s message loop to process the results.
You can also enable strict mode (available in Gingerbread) to provide visual feedback when your application performs a naughty operations on the UI-thread.
Handling large bitmap images on Android is hard. We still haven’t found the silver bullet that helps us load as many images as we want without running out of memory.
The main problem is that the amount of RAM available to individual processes in Android applications is disappointingly small. The maximum heap size keeps getting bigger and bigger with successive OS releases and fancier devices, but it’s hard to believe that we’ll ever have the luxury to load as many huge images as we could in desktop environments.
The math is simple. The resolution of the Galaxy Nexus screen is 1280×720 pixels. Images with a bit-depth of 32-bits-per-pixel will consume about 3.5 MB of memory once they are uncompressed into your application’s heap. It doesn’t matter what kind of compression the image uses.
Most applications seem to get heap spaces around 20 to 30 MB. You can see that loading only a handful of images into memory can cause your application to run dry of heap space very quickly. You can try using the android:largeHeap attribute in your application Manifest to request more heap space, but, at best, this attribute is just a hint and the operation system doesn’t need to respect it.
What can you do? First, make sure that you are not leaking references to your images when you’re done. You want to get that image off of your heap as soon as possible.
This problem is simple to solve, but I’ve seen it done poorly so many times. Your application needs to give positive feedback when the user interacts with the application’s display. If you touch a button, it should be highlighted.
Android makes it easy to provide different graphical states for on-screen elements based on their current selection or pressed states. You need to assign a StateListDrawable to your custom screen elements. The easiest way to do this is to create a drawable XML file with a state selector (see the above link for an example).
Think carefully about where to apply these kinds of drawable. You probably won’t need it on regular Button objects (as long as you are using one of the built-in themes), but you will definitely need it on ImageButtons. You may or may not need to use it on individual rows in ListViews. Be careful.
A lot of people wants us to port existing iOS apps to the Android platform and want to recycle the same design. That’s a horrible taboo to break. Android applications have their own look-and-feel that is distinct from iOS and other platforms. What makes sense on iOS doesn’t always make sense on Android. Android users are smart and will call out and give poor ratings to Android applications that look like iOS applications.
Google has written extensive Design Guidelines elaborating on how Android applications should look. Read it! Learn it! Some design rules are made to be broken and you can distinguish your application by bending the rules in shrewd ways — but you should learn the rules before you play ball.
Subscribe to the Android Niceties tumblr blog for inspiration.
A particularly frequent transgression is to put tabs at the bottom of the screen. The built-in Android tab controls should live at the top of the screen.
Android device fragmentation is real. There’s lots of versions of the operating system, lots of screen sizes, and lots of keyboard layouts in the ecosystem. Many applications do a poor job of supporting the vast diversity of devices in the world.
It doesn’t have to be so hard. Android gives developers many tools to combat this bewildering space. Here’s some things to remember: