Android Crossword Helper
I've been working with mobile phone software for years and have played with Symbian, Windows Mobile and BlackBerry before now, but Android has my interest piqued. It's all open-source, it's all Java and it uses as its standard development environment Eclipse, by far my favourite IDE.
One of the things many Android applications need to do is retrieve information from somewhere on the web, and another is to display results in lists so I've put together some notes on how to start going about this. You can download all code and resources I refer to.
If you're just getting into Android, you'll find plenty of resources at developer.android.com. If you're familiar with Java, be prepared to learn something new, because Android development has as many of its own foibles as any web or Swing application, and it will have to run on a variety of mobile devices, with differences in performance, screen size and network connectivity!
I'll presume that you're familiar with creating an Android application in Eclipse and have installed and configured the SDK.

What the App Will Do
This is a very simple application that allows its user to enter parts of a word with missing letters and to then retrieve all possible matches. It needs an active connection to the Internet and has very little in the way of graceful error handling or other such niceties!
How it Works
The Android app featured here contacts a web service using a standard GET request and formats the results returned. The web service in question is a very simple application running on WyredMedia's web server, and looks up words in a MySQL database. Before using this app on your daily crossword, you should be aware that this database contains a far-from-complete collection of words!
Since interacting with the web server is relatively time-consuming, and because it is imperative that we don't freeze the phone whilst communication takes place, the interaction is performed in a separate thread from the one in charge of the user interface on the Android phone. Using Android's 'callback' system, the UI (user interface) thread can be made to show the results when the work of the communication thread is done.
Creating the Activity
Having worked on Swing applications, I might choose to create the screen layout purely in code, but Android seems to have slightly closed the gap between UI designer and coder far more quickly than Sun (now Oracle) managed with JavaFX, and I opt instead to make full use of the XML layout file option, with DroidDraw providing a neat shortcut to the creation of your first such file.
Not a ListActivity
Most Android examples showing how to provide information in a list do so through a ListActivity, which is a very handy way to create an application where a list fills the whole screen, but this isn't always what you want, and you can easily include a scrollable list in an otherwise static page by simply extending Activity instead.
Important Components
The important components (widgets) in use here are:
- TextView called txtConvertValueInput, which is where the user types letters from the word to be found;
- Button called btnGo, which starts the process of requesting and receiving possible matches;
- ListView called lstResults to show the results.
Important Bits of Code
The Activity's onCreate method sets up the main content view and then calls this initView() method, which gets a hold of the components that have a part to play in its operation:
/*** Get references to widgets and prepare click listeners for buttons.*/private void initView() {
txtConvertValueInput = (EditText) findViewById(R.id.txtConvertValueInput);
btnGo = (Button) findViewById(R.id.btnGo);
btnReset = (Button) findViewById(R.id.btnReset);
lstResults = (ListView) findViewById(R.id.lstResults);
btnGo.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
getWordsFromWeb();
}});
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reset();
}});
}
The key tasks here are to get a handle on the input field txtConvertValueInput and results list lstResults, and to create listeners to make the 'Go' and 'Reset' buttons respond.
The 'Reset' key simply clears the input field and results list, but the 'Go' button calls this getWordsFromWeb function:
/*** Called in response to a 'Go' button click, prepares one Runnable item* for running on completion of the retrieval via HTTP, and a new Thread* to do the (potentially time-consuming) retrieval.*/private void getWordsFromWeb() {
/** The input text.*/final String search = txtConvertValueInput.getText().toString();
/** A Handler is created to handle the completion of a task that will* take place outside of the main thread.*/final Handler callback = new Handler();
/** Prepare a Runnable task for execution once the time-consuming task* has completed, but don't run it yet of course!*/final Runnable displayRunner = new Runnable() {
@Override
public void run() {
displayResults();
}};
/** Start a new Thread to do the data-retrieval...*/new Thread() {
@Override
public void run() {
/** ... with a simple run() method that calls a method to do the* actual work...*/doGetWordsFromWeb(search, 0);
/** and then sends displayRunner to the Handler's post method* so it can be run.*/callback.post(displayRunner);
}}.start();
}
Notice how the Runnable object whose job is to update the UI is prepared before a new Thread is created to do the retrieval work. Android uses a Handler methodology to make this happen: once the retrieval is done (by the call to doGetWordsFromWeb on line 131, the Handler is prodded to make the GUI update part happen: line 136 effectively gets the code on line 117 executed in the correct thread!
Now, the actual process of getting sending the request and receiving the response from our web service. In this example, the service has a single endpoint, and delivers a single string containing matching words, delimited by the pipe ('|') character.
/*** Call the HTTP service and retrieve results based on the search text.* <p>* Because this method isn't run in the main (UI) thread, it can't update* the results list, so instead it sets the member results array so that* it can be used when {@link #displayResults()} is called.* </p>*/private void doGetWordsFromWeb(String search, int limit) {
try {
/** Prepare basic params for the HTTP connection...*/final HttpParams params = new BasicHttpParams();
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT_MS);
HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT_MS);
/** ... prepare the client, the GET method and the HttpResponse to* handle the results...*/final HttpClient client = new DefaultHttpClient();
final HttpGet get = new HttpGet(createWordsUri(search, limit));
final HttpResponse response = client.execute(get);
/** ... and read those results having executed that GET.*/final char[] buf = new char[512];
final BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
final StringWriter writer = new StringWriter();
int n;
while ((n = reader.read(buf)) != -1)
writer.write(buf, 0, n);
reader.close();
/** Now we have the results, in a single string delimited with the* '|' (pipe) character.*/final String results = writer.toString();
/** Make a DEBUG entry in the log.*/Log.d("WyredWorld", "Got \"" + results + "\"");
/** Split the results string on the pipe character and store in the* results member array ready for the UI thread to read.*/this.results = results.split("\\|");
} catch (final Exception e) {
String message = e.getMessage();
Log.e("WyredWorld", message == null ? "HTTP GET failed" : message, e);
}}
The big thing here is the updating of the member results array in one thread (line 151) to be used for populating the list by another (the original GUI) thread.
The last bit worth mentioning is the update to the ListView, contained in the displayResults method:
/*** Updates the results list with data returned in response to the HTTP* request.*/private void displayResults() {
if (results != null) {
/** The results list is updated by providing it with a new Adapter,* which in turn is passed the results array.** Notice that the setAdapter method doesn't refer to listResults* by name, but instead the standard simple_list_item_1 member of* android.R.layout (not the R resources file automatically built* as part of your project!).*/lstResults.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results));
} else {
lstResults.setAdapter(new ArrayAdapter<String>(this,
R.id.lstResults, new String[] {}));
}}
The comments in this block of code do all the explaining; the most important point being the reference to a standard android.R.layout.simple_list_item_1 as the identification of the ListView, even though has an id of lstResults.
Improve the Code!
The code is available for you to download and play with, and there are plenty of 'next steps'. Apart from making the whole thing look nicer, top of the list would have to be:
- Indication that communication is taking place, perhaps with a timer made visible just before calling doGetWordsFromWeb and hidden once the list has been updated.
- Check for availability of the network. There is no such check at the moment and, failing to reach the server, the app will simply not update and will not inform the user of the reason.
| Attachment | Size |
|---|---|
| CrossWyred.zip | 13.74 KB |

Comments
how would you go about
how would you go about creating this so it worked by reading from a local dictionary file rather than across a http connection?
i have a dictionary txt file with about 250,000 words (saved as dictionary.png so android thinks it is compressed).
Interesting stuff thanks, at
Interesting stuff thanks, at least once you got eclipse all set up ;)
Just a little thing- I think your ref to line 137 should read 136!
Scott
Eagle-eyed!
Ah yes, well spotted... thank you!