This article covers some of the Android SDK tools for dealing with tricky situations. To develop Android applications, you will need the latest Android SDK which requires a Java Development Kit (JDK). I used Android 2.2 and JDK 1.6.0_17 (see Resources for links to these tools). It is not required that you have a physical device; all of the code in this article will run fine on the Android emulator that comes with the SDK. You should be familiar with Android programming as this article will not cover basic Android development, but you can probably follow along if you have knowledge of the Java programming language.
One of the most common tasks for Android applications is to retrieve or send data over
the network to a remote server. Often the result of this operation is some new data
that you want to display to the user. That means you need to modify the user
interface. Most developers know that you should not perform a potentially long-running
task, such as accessing data over the network (especially on mobile phones that might
have a very slow network connection), on the main UI thread. Doing so will freeze your
application until the long-running task completes. In fact, if this task takes more than five seconds, the Android operating system will
reward your application with the infamous Application Not
Responding dialog in Figure 1.
Figure 1. Android's infamous Application Not Responding dialog
You never know just how slow the user's network connection might be. To avoid tempting fate, you must perform tasks like these on a different thread, or at least not on the main UI thread. Many, if not most, Android applications need to deal with multiple threads and thus concurrency. Applications often need to persist data locally, and Android's local database is an appealing option. In all three of these scenarios (different threads, concurrency, and persisting data locally), there are some standard ways to do these things in a Java environment. However, as you will see, Android offers some different options. Let's take a look at each of these, as well as their pros and cons.
Making a call over the network in Java programming is straightforward. The familiar java.net package contains several classes for doing this. Most of
these classes are also present in Android, and, in fact, you can use classes like
java.net.URL and java.net.URLConnection just like you would in any other Java application. However, Android includes the Apache HttpClient library. This is the preferred way to do networking on Android. Even if you use the usual Java classes, Android's implementations will still use the HttpClient. Listing 1 shows an example of using this essential library. (See Downloads for all of the source code.)
Listing 1. Using the Http Client library on Android
private ArrayList<Stock> fetchStockData(Stock[] oldStocks)
throws ClientProtocolException, IOException{
StringBuilder sb = new StringBuilder();
for (Stock stock : oldStocks){
sb.append(stock.getSymbol());
sb.append('+');
}
sb.deleteCharAt(sb.length() - 1);
String urlStr =
"http://finance.yahoo.com/d/quotes.csv?f=sb2n&s=" +
sb.toString();
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(urlStr.toString());
HttpResponse response = client.execute(request);
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line = reader.readLine();
int i = 0;
ArrayList<Stock> newStocks = new ArrayList<Stock>(oldStocks.length);
while (line != null){
String[] values = line.split(",");
Stock stock = new Stock(oldStocks[i], oldStocks[i].getId());
stock.setCurrentPrice(Double.parseDouble(values[1]));
stock.setName(values[2]);
newStocks.add(stock);
line = reader.readLine();
i++;
}
return newStocks;
}
|
In this code, you take in an array of Stock objects. These are basic data structure
objects that hold information about a stock that a user owns (such as symbol, price, and so
on) along with more personal information such as how much the user paid for it. You
retrieve dynamic data from Yahoo Finance (for example, the current price of the
stock) using the HttpClient class. The HttpClient takes an HttpUriRequest and,
in this case, you use HttpGet, a subclass of HttpUriRequest. Similarly, there is an HttpPost class for times when you need to post data to a remote server. Once you get the HttpResponse from the client, you can get to the underlying InputStream of the response, buffer it, and parse it to get the stock data.
Now that you have seen how to retrieve data over the network, look at how to use this data to smartly update the Android UI using multi-threading.
Android concurrency in practice
If you run the code in Listing 1 on the main UI thread of an
application, it might cause an Application Not Responding
dialog to appear, depending upon the speed of the user's network. So be sure to spawn a thread to fetch this data. Listing 2 shows one way to do this.
Listing 2. Naïve multithreading (don't do this, it won't work!)
private void refreshStockData(){
Runnable task = new Runnable(){
public void run() {
try {
ArrayList<Stock> newStocks =
fetchStockData(stocks.toArray(
new Stock[stocks.size()]));
for (int i=0;i<stocks.size();i++){
Stock s = stocks.get(i);
s.setCurrentPrice(
newStocks.get(i).getCurrentPrice());
s.setName(newStocks.get(i).getName());
refresh();
}
} catch (Exception e) {
Log.e("StockPortfolioViewStocks",
"Exception getting stock data", e);
}
}
};
Thread t = new Thread(task);
t.start();
}
|
The caption on Listing 2 states that it is naïve code, and indeed it
is. In this simple example, you call the fetchStockData
method from Listing 1 by wrapping it in a Runnable object and executing it on a new thread. In this new thread,
you then access stocks, a member variable of the enclosing Activity
(the class that creates the UI). As the name
suggests, this is a data structure (in this case, a java.util.ArrayList) of Stock objects. To
put it another way, you are sharing data between two threads, the main UI thread and
the spawned thread (called in the code Listing 2). Once you modify the shared
data in the spawned thread, you update the UI by calling the refresh method on the Activity object.
If you have programmed Java Swing applications, you might have followed a pattern like
this. However, this will not work in Android. The spawned thread will not be able to
modify the UI at all. So how do you retrieve data without freezing the UI, but in a
way that allows you to modify the UI once that data has been received? The android.os.Handler class allows you to coordinate and communicate
between threads. Listing 3 shows an updated refreshStockData method that uses a Handler.
Listing 3. Multithreading that actually works—by using a
Handler
private void refreshStockData(){
final ArrayList<Stock> localStocks =
new ArrayList<Stock>(stocks.size());
for (Stock stock : stocks){
localStocks.add(new Stock(stock, stock.getId()));
}
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
for (int i=0;i<stocks.size();i++){
stocks.set(i, localStocks.get(i));
}
refresh();
}
};
Runnable task = new Runnable(){
public void run() {
try {
ArrayList<Stock> newStocks =
fetchStockData(localStocks.toArray(
new Stock[localStocks.size()]));
for (int i=0;i<localStocks.size();i++){
Stock ns = newStocks.get(i);
Stock ls = localStocks.get(i);
ls.setName(ns.getName());
ls.setCurrentPrice(ns.getCurrentPrice());
}
handler.sendEmptyMessage(RESULT_OK);
} catch (Exception e) {
Log.e("StockPortfolioViewStocks",
"Exception getting stock data", e);
}
}
};
Thread dataThread = new Thread(task);
dataThread.start();
}
|
There are two major differences between the code in Listing 2 and Listing 3. The obvious difference is the presence of the Handler. The second is that, in the spawned thread, you do not modify
the UI. Instead you send a message to the Handler, and the
Handler then modifies the UI. Also, notice that, in the
thread, you do not modify the stocks member variable, as
you did previously. Instead you modify a local copy of the data. This is not strictly necessary, but it is safer.
Listing 3 demonstrates what turns out to be a very common pattern in
concurrent programming: copying data, passing it to a new thread that performs some
long task, passing the resulting data back to the main UI thread, and then updating
the main UI thread with said data. Handlers are the main
communication mechanism for this in Android, and they make this pattern easier to
implement. However, Listing 3 still has a lot of boilerplate code. Luckily, Android provides a way to encapsulate and eliminate most of this boilerplate code. Listing 4 demonstrates this.
Listing 4. Easier multithreading with an
AsyncTask
private void refreshStockData() {
new AsyncTask<Stock, Void, ArrayList<Stock>>(){
@Override
protected void onPostExecute(ArrayList<Stock> result) {
ViewStocks.this.stocks = result;
refresh();
}
@Override
protected ArrayList<Stock> doInBackground(Stock... stocks){
try {
return fetchStockData(stocks);
} catch (Exception e) {
Log.e("StockPortfolioViewStocks", "Exception getting stock data", e);
}
return null;
}
}.execute(stocks.toArray(new Stock[stocks.size()]));
}
|
As you can see, Listing 4 has much less boilerplate code than Listing 3. You do not create any threads or Handlers. You use the AsyncTask to
encapsulate all of that. To create an AsyncTask, you must
implement the doInBackground method. This method will
always be executed in a separate thread, so you are free to call long-running tasks.
Its input type comes from the type parameter of the AsyncTask that you create. In this case, the first type parameter was
Stock, so doInBackground gets an
array of Stock objects passed into it. Similarly, it
returns an ArrayList<Stock> because that is the third
type parameter of the AsyncTask. In this example, I also chose to override the onPostExecute method. This is an optional method that you will want to implement if you need to do anything with the data that comes back from doInBackground. This method will always be executed on the main UI thread, so it is ideal for modifying the UI.
With AsyncTask, you can really simplify multithreaded code.
It removes many of the concurrency pitfalls from your development path. However, you
still might find some potential problems with AsyncTask such as
what happens when the orientation changes on the device while the doInBackground method in an AsyncTask
object is executing. See the links in Resources for some
techniques on how to deal with cases such as this.
Now let's move on to another common task where Android diverges significantly from the usual Java way—working with databases.
One very useful feature in Android is the presence of a local relational database. Sure
you can store your data in local files, but often it is more useful to store it using
a Relational Database Management System (RDBMS). Android gives you the popular SQLite
database to work with, as it is highly optimized for embedded systems like Android. It
is used by many core applications on Android. For example, the user's address book is stored in a SQLite database. Now, given Android's Java implementation, you might expect to access these databases using JDBC. Surprisingly, Android even includes the java.sql and javax.sql packages that constitute the bulk of the JDBC API. However, these turn out to be of no use when it comes to working with local Android databases. Instead, you will want to use the android.database and android.database.sqlite packages. Listing 5 shows an example of using these classes to store and retrieve data.
Listing 5. Database access with Android
public class StocksDb {
private static final String DB_NAME = "stocks.db";
private static final int DB_VERSION = 1;
private static final String TABLE_NAME = "stock";
private static final String CREATE_TABLE = "CREATE TABLE " +
TABLE_NAME + " (id INTEGER PRIMARY KEY, symbol TEXT, max_price DECIMAL(8,2), " +
"min_price DECIMAL(8,2), price_paid DECIMAL(8,2), " +
"quantity INTEGER)";
private static final String INSERT_SQL = "INSERT INTO " + TABLE_NAME +
" (symbol, max_price, min_price, price_paid, quantity) " +
"VALUES (?,?,?,?,?)";
private static final String READ_SQL = "SELECT id, symbol, max_price, " +
"min_price, price_paid, quantity FROM " + TABLE_NAME;
private final Context context;
private final SQLiteOpenHelper helper;
private final SQLiteStatement stmt;
private final SQLiteDatabase db;
public StocksDb(Context context){
this.context = context;
helper = new SQLiteOpenHelper(context, DB_NAME, null,
DB_VERSION){
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
throw new UnsupportedOperationException();
}
};
db = helper.getWritableDatabase();
stmt = db.compileStatement(INSERT_SQL);
}
public Stock addStock(Stock stock){
stmt.bindString(1, stock.getSymbol());
stmt.bindDouble(2, stock.getMaxPrice());
stmt.bindDouble(3, stock.getMinPrice());
stmt.bindDouble(4, stock.getPricePaid());
stmt.bindLong(5, stock.getQuantity());
int id = (int) stmt.executeInsert();
return new Stock (stock, id);
}
public ArrayList<Stock> getStocks() {
Cursor results = db.rawQuery(READ_SQL, null);
ArrayList<Stock> stocks =
new ArrayList<Stock>(results.getCount());
if (results.moveToFirst()){
int idCol = results.getColumnIndex("id");
int symbolCol = results.getColumnIndex("symbol");
int maxCol = results.getColumnIndex("max_price");
int minCol = results.getColumnIndex("min_price");
int priceCol = results.getColumnIndex("price_paid");
int quanitytCol = results.getColumnIndex("quantity");
do {
Stock stock = new Stock(results.getString(symbolCol),
results.getDouble(priceCol),
results.getInt(quanitytCol),
results.getInt(idCol));
stock.setMaxPrice(results.getDouble(maxCol));
stock.setMinPrice(results.getDouble(minCol));
stocks.add(stock);
} while (results.moveToNext());
}
if (!results.isClosed()){
results.close();
}
return stocks;
}
public void close(){
helper.close();
}
}
|
The class in Listing 5 completely encapsulates a SQLite database used
for storing stock information. Because you are working with an embedded database that
will not only be used by your application, but will also be created by it, you have to
provide code for creating the database. Android provides a useful abstract helper
class for this called SQLiteOpenHelper. To implement this,
you extend this abstract class and supply code to create your database in its
onCreate method. Once you have an instance of this helper,
you can get an instance of SQLiteDatabase which you can use
to execute arbitrary SQL statements.
Your database class has a couple of convenience methods. The first one is addStock for saving a new stock to the database. Notice that you use a SQLiteStatement instance. This is similar to a java.sql.PreparedStatement. Notice how it is compiled in your class's constructor, so it can be reused each time addStock is called. On each addStock invocation, the SQLiteStatement's variables (the question marks in the INSERT_SQL string), are bound to the data passed in to addStock. Again, this is very similar to the PreparedStatement that you are probably familiar with from JDBC.
The other convenience method is getStocks. As the name
suggests, this retrieves all of the stocks from the database. Notice that you once
again use a SQL string for this, just as you would in JDBC. You do this using the
rawQuery method on the SQLiteDatabase class. This class also has several query methods that
let you query databases without using SQL directly. All of these various methods
return a Cursor object which is very similar to a java.sql.ResultSet. You can move the Cursor over the rows of data that are returned from your query. On
each row, you can use the getInt, getString, and other methods to retrieve the values
associated with the various columns of the database table that you query. Again, this
is very similar to a ResultSet. Also similar to a ResultSet, it is important to close a Cursor once you are done with it. If you do not close your Cursors, then you might quickly run out of memory and cause your application to crash.
Querying a local database can be a slow process, especially if you have many rows of
data or you need to start running complex queries that join multiple tables. While it
is unlikely that any database queries or insertions will take more than five seconds
and cause an Application Not Responding dialog to appear, it is still not advisable to potentially freeze your UI while your code is busy reading and writing data. Naturally, the easiest way to avoid this situation is to use AsyncTask. Listing 6 shows an example of this.
Listing 6. Inserting to the database on a separate thread
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String symbol = symbolIn.getText().toString();
symbolIn.setText("");
double max = Double.parseDouble(maxIn.getText().toString());
maxIn.setText("");
double min = Double.parseDouble(minIn.getText().toString());
minIn.setText("");
double pricePaid =
Double.parseDouble(priceIn.getText().toString());
priceIn.setText("");
int quantity = Integer.parseInt(quantIn.getText().toString());
quantIn.setText("");
Stock stock = new Stock(symbol, pricePaid, quantity);
stock.setMaxPrice(max);
stock.setMinPrice(min);
new AsyncTask<Stock,Void,Stock>(){
@Override
protected Stock doInBackground(Stock... newStocks) {
// There can be only one!
return db.addStock(newStocks[0]);
}
@Override
protected void onPostExecute(Stock s){
addStockAndRefresh(s);
}
}.execute(stock);
}
});
|
You start by creating an event listener for a button. When the user clicks the button,
you read the stock data from various widgets (EditText widgets to be exact) and
populate a new Stock object. You create an AsyncTask and invoke the addStock method
from Listing 5 through the doInBackground
method. Thus, addStock will execute on a background thread,
not on the main UI thread. Once it completes, you pass the new Stock object from the database to the addStockAndRefresh method that executes on the main UI thread.
This article has shown how, even though Android only supports a subset of the many APIs in the Java environment, it is definitely not lacking in terms of capabilities. In some cases, such as networking, it fully implements familiar APIs but provides some more convenient ways to do things as well. In other cases, such as with concurrency, Android adds extra APIs and conventions that must be followed. Finally, in the case of database access, Android provides a completely different way to access databases, but with many familiar concepts. These aren't just arbitrary differences between standard Java and Android's Java technologies: They form some of the fundamental building blocks of Android development.
| Description | Name | Size | Download method |
|---|---|---|---|
| Article source code | StockPortfolio.zip | 18KB | HTTP |
Information about download methods
Learn
- Working with XML on Android (Michael Galpin, developerWorks, June 2009): Learn even more about the different ways to parse XML using the Android SDK.
- Develop Android applications with Eclipse (Frank Ableson, developerWorks, February 2008): Android provides a great Eclipse plugin to accelerate your app development. Learn about it in this tutorial.
- Networking with Android (Frank Ableson, developerWorks, June 2009): If your application will be getting data over the network you will want to read this article.
- Introduction to Android development (Frank Ableson, developerWorks, May 2009): Just starting out on Android? This developerWorks article is a great place to start.
- Android and iPhone browser wars, Part 1: WebKit to the rescue (Frank Ableson, developerWorks, December 2009): See how you can leverage the features of mobile browsers in this article.
- Introducing Droid-Fu: Read about some of the pitfalls of AsyncTask and how they can be avoided in this blog entry.
- More articles by this author (Michael Galpin, developerWorks, April 2006-current): Read articles about Android, XML, HTML 5, Eclipse, Apache Geronimo, Ajax, more Google APIs, and other technologies.
- XML area on developerWorks: Get the resources you need to advance your skills in the XML arena.
- My developerWorks: Personalize your developerWorks experience.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks. Also, read more XML tips.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- developerWorks on Twitter: Join today to follow developerWorks tweets.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- Android SDK: Download the Android SDK. Version 1.5 and later will work for this article's exercise.
- Java Development Kit: Download the complete platform and runtime environment for JDK 1.6.0_17, used in this article.
- Android Open Source Project: Get the open source code for Android.
- IBM product evaluation versions: Download or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks blogs: Check out these blogs and get involved.

Michael Galpin is an architect at eBay. He is a frequent contributor to developerWorks. He has spoken at various technical conferences, including JavaOne, EclipseCon, and AjaxWorld. To get a preview of what he is working on next, follow @michaelg on Twitter.



