I recently completed a major version of an Android client for work. I guess no program is every really “complete”. But, it’s at a good stopping point for the moment so i thought i would jot down some of the lessons i learned. These can really apply to any type of development, not just mobile Android.
- The network layer is unreliable
First of all, cell phones have flaky connections that come and go. They might be on wi-fi, they might be on a cell connection. They might be in a tunnel. Maybe they’re in airplane mode. Doesn’t matter. You can’t count on a network always being there, and even when it is there, you have to assume that it will be flaky and return strange errors. It’s important to have a robust network layer that has retries built into it for various errors such as timeouts, unavailable, etc. Don’t just assume the backend is down. Assume first that their connection is temporarily out of sorts, retry a few times, and THEN give up. That will eliminate 90% of the network errors a user has to be aware of. Oh, and some phones, vendors, flavors of Android all have weird little network quirks that only they exhibit. Yet another reason for a robust network abstraction.
- Deal with threading issues
If you don’t want to die from a thousand little cuts, design your code to be thread-safe from the beginning. Many phones now have multiple cores and really do execute things in parallel. Add to that fact that any complex app will likely have multiple IO requests in flight at the same time (whether from the file system, database, or network) that can return asynchronously, and you are ripe for threading problems. Deadlock, data switching out from underneath you, etc. Use the threading tools. Synchronize, lock, atomic operations and especially the concurrent package are your friend.
- Be asynchronous
Seriously. Don’t block the UI thread for any reason. If you’re loading a file from the file system, accessing the database, making a network call, or even doing some heavy number crunching, do it on a thread and call back to the UI when you’re done. Android has some nice abstractions to help with this, including AsyncTask, and Handler classes. You can also do traditional Runnable’s if you like. But whatever method you use, make sure you have an async layer built into your app that’s easy to use. Make sure your main application logic can deal with everything being asynchronous. Your users will thank you for a snappy app. Corollary: Don’t block the UI needlessly with modal dialogs unless you absolutely have to wait for a result. Let the user do other things while your background processes are running.
- Be aware of constrained resources
Ya this is a fun one. You have very limited memory in which your application can run. We’re not on a desktop here. Some phones are far worse than others as far as how much memory they let you have. Loading images is especially dangerous for running out of memory. Have a strategy in place to only keep in memory what you need. Don’t keep things lying around longer than you must. Memory is fast, but disk is cheap and certainly faster than the network and definitely better to take a few milliseconds to reload an image from the drive all the time rather than running out of memory and crashing the program. So load it from the network, save it to disk, cash in memory until you run out, then just have some type of LRU cache.
- Understand and work with the application lifecycle
This one may be somewhat android specific, but the general idea is sound for anything: Each activity (screen/window) has a lifecycle. It’s created, setup, running, paused, and eventually destroyed. It might also be resumed and restored in the middle of all that. The framework provides rules about when all these things happen and how you should deal with them. Make sure you do the correct thing at the correct time. Expect that since this is a mobile environment with lots of stuff going on that your activity might be asked to pause or shutdown at any time, even mid-process. Save off your state, be able to restore it, and know how to deal with data inconsistencies that might result. Don’t expect that x then y then z will always happen. X and Y might happen, and you’ve started Z, but then a phone call comes in and your activity goes away. When you come back, what do you do? Make sure you do the right thing.