Getting Started with Android Development

I thought I’d give some tips to those of you interested in getting started with Android.  A few weeks ago I launched my first and only Android app, FoneDoktor, after developing it for about three months.  Overall my experience was very positive — the Android docs and community are both amazing.

Getting Started with the Basics

The Android developer docs (developer.android.com) are amazing.  The first thing you should do is read up on the basics, and here’s a good starting point:

  1. Application Fundamentals
  2. Development Environment Introduction
  3. Activities and Services
  4. Intents
  5. User Interface

Next, I strongly recommend following the Notepad Tutorial, which will guide you through building a basic app. See my notes on the development environment below before you get started.  And actually write the code, don’t just read through the tutorial.

Development Environment

Use Eclipse.  The Android SDK has an Eclipse plugin that is worth learning Eclipse for.  It can create signed and unsigned APK files, run the emulator, manage virtual devices and API levels.  It more or less makes all the shitty development tasks easy.  Use Eclipse even if you aren’t familiar with it.  The ADT plugin is covered in detail here.

General Development Advice

Use lots of logging.  adb‘s logcat program is great and makes filtering logs very easy.  Keep UI work within Eclipse at first, using the XML editors and renderers as a first try, and moving to either a physical device or the emulator to be sure the UI is polished.  I tended to prefer developing on a physical phone docked right in front of my keyboard.  The emulator is annoying to use with a mouse, though it is slightly faster to send new code to.  Oh and don’t stop the emulator every time you want to try some new code — the Eclipse plugin does the right thing and only updates the app you’re working on in the emulator.

API Version

You’ll be tempted to use one of the higher, recently released APIs such as Gingerbread or Ice Cream Sandwich, but what you’ll find is that most people are still on 2.2 (I forget its release name). Start developing on 2.2 and only discover and love the newer and better APIs as you make your app work on later versions of Android. Starting on 2.3 or 2.4 will only frustrate you when you need to use older and worse APIs for 2.2.

The Eclipse plugin makes selecting API versions very easy.

HTTP Requests

Make sure that whenever you do any HTTP request (or anything with IO blocking for that matter), you do it in the background. There are several alternatives for doing background processing, each with different advantages.  Read about Services, IntentServices, and AsyncTask.  Once you read about them you’ll understand which is good for what purpose.

I used Apache’s HTTP libraries to make HTTP requests.  They worked great.  I don’t know Java all that well, so I’m not sure if there are better alternatives.  I hear Roboguice has good HTTP and JSON support, though I never played with it.

Polling and Receiving Data from the Server

Most apps have a server component, where the app interacts with a server in the background.  I used the AlarmManager to fire off a background process every 15 minutes, which would make a HTTP request asking for more data.  Using the AlarmManager is ideal because it helps Android schedule recurring jobs in a battery-efficient way, and it also guarantees that whatever background service you’re running will be scheduled accordingly and not de-prioritized.

I used Android’s built-in JSON support to serialize and deserialize JSON data.  It worked great.

Threading

Don’t roll your own threading solutions. Use what I’ve outlined above (Service, IntentService, AsyncTask) instead.

Font Size

Font size was probably the biggest gotcha for me. For whatever reason some devices don’t respect px and pt as font size units. Instead use sp units.  Without sp units font sizes will be different depending on the device, which turns out to be a debugging nightmare.

Exception Handling

If you have an app that starts itself on startup, don’t ever let it throw an Exception, otherwise the user will need to restart the app themselves.  Look into Exception handling services that will catch the exception for you and log it somewhere.  I don’t know which of these systems is the best (I’m not using one of them), but I know they exist.  If you’re more OK with your app crashing and throwing an Exception to the end user, the good news is the Android marketplace will collect all the errors that occur and give you a full stack trace explaining them.  Although, probably obviously, the user experience of getting an Exception is pretty awful.

Caching

Cache data whenever you collect it from a HTTP request.  There are a few reasons for this.  First, with cached data you’ll be able to display information to the user without requiring an internet connection.  Second, you’re able to display data immediately while a background HTTP request is made to fetch new data.  And third, since your app will either be updated by the user (when the app is opened or with the refresh button is pressed) or by the AlarmManager, having a cache around will let you create a better user experience while data is either stale or waiting to be fetched.

Depending on your data you can either use the built-in sqlite3 database, or SharedPreferences.  SharedPreferences are great for key-value data, whereas sqlite3 is great for more relational or complex data, which includes data that requires more complex querying.  Learn more about data storage in general here.

UI Layouts

Android offers several layout alternatives such as RelativeLayout and LinearLayout.  Many of these layouts work in obscure, odd ways.  Read their docs in full before you start hammering away at XML.  The time you spend reading upfront will save lots of debugging time down the road, trust me.

Data Records

If your app will have several different types of stored data (e.g., user profiles, messages, game objects, feed items, etc), definitely create a Record interface–with each record type implementing it–that can be easily stored in sqlite, packaged in a JSON HTTP request, or sent between Intents as a Parcelable.  For example, create a User.java, Message.java, etc., where each class can send or receive a new or set of records via HTTP and serialize/deserialize as JSON, be stored to and read from sqlite3 with Cursors and ContentValues, and be sent across intents as a Parcelable.  Really it’s too bad that Android doesn’t provide this for you — a serialization format that works in both sqlite3, intents, and HTTP requests — but oh well.  I never looked into other serialization alternatives such as Protocol Buffers or Thrift.

Getting Help

Whenever I was stuck I’d always consult Google and stackoverflow for guidance. The Android community on stackoverflow is amazing.  You’ll find most answers to your questions on stackoverflow. I never tried the IRC channel, though I hear it’s good, too.

Conclusions

I had a lot of fun learning and working on Android.  All other development tools and platforms should use Android as an example for how to make developers happy (I’m looking at you, Ruby and Rails).  And the community is blooming and accessible.

Hopefully this guide can help you get started with Android.  I’ll update it as I think of new bits of advice to give.  Otherwise don’t hesitate to ask me questions in the comments, and don’t hesitate to share any advice you’ve learned as well.

Android SQLiteOpenHelper onCreate() and onUpgrade() Semantics

Overall I’ve been insanely impressed with Android’s documentation.  I’d even go so far to say that the Android platform has the best documentation of any platform or technology I’ve ever learned, including Django and Python.

However, I couldn’t find much on the semantics of the onCreate() and onUpgrade() methods in android.database.sqlite.SQLiteOpenHelper, which is a class that helps you open and upgrade a SQLite database.  I’ll describe below how these methods are called when databases are created and upgraded.

Database Creation

When the SQLite database is constructed for the first time, as you’d expect the onCreate() method is called, creating the tables you’ve defined and executing any other code you’ve written.  However, this method will only be called if the SQLite file is missing in your app’s data directory (/data/data/your.apps.classpath/databases).  This method will not be called if you’ve changed your code and relaunched in the emulator.  If you want onCreate() to run you need to use adb to delete the SQLite database file.  The sqlite3 tool description has more context here.

Database Upgrading

The constructor of your implementation of SQLiteOpenHelper should call the super constructor, passing along the database name and version.  The onUpgrade() method will only be called when the version integer is larger than the current version running in the emulator.  If you want the onUpgrade() method to be called, you need to increment the version number in your code.