Sie sind auf Seite 1von 42

Build dynamic user interfaces with Android and XML

Collect data using an Android forms engine


Frank Ableson Entrepreneur MSI Services, Inc. Skill Level: Intermediate Date: 07 Sep 2010

A number of websites cater to non-profits that provide easily set-up and used forms for taking polls and collecting data. This tutorial introduces a simple architecture for designing similar applications for Androiddynamic user interfaces that allow non-programmers to collect data from mobile users. You will create an example forms engine in this tutorial with both server and mobile sides.

Section 1. Before you start


You should be comfortable constructing Android applications with the Android SDK to get the most from this tutorial. After completion, you will have learned how to perform application-to-web server communications with HTTP(S) and how to parse XML with the DOM parser. Along the way, you will create custom and dynamic user interface layouts, multi-threaded communications, message handlers, and progress dialogs. To a lesser degree, you will learn about AndroidManifest.xml and server side scripting.

About this tutorial


Frequently used acronyms
API: Application Programming Interface DOM: Document Object Model HTML: HyperText Markup Language HTTP(S): Hypertext Transfer Protocol Secure IDE: Integrated development environment SAX: Simple API for XML SDK: Software Development Kit UI: User Interface Trademarks Page 1 of 42

Copyright IBM Corporation 2010 Build dynamic user interfaces with Android and XML

developerWorks

ibm.com/developerWorks/
URL: Uniform Resource Locator XML: Extensible Markup Language

This tutorial introduces an architecture for dynamic forms for mobile data collection on Android devices. I will begin with a high level architecture and discussion of where such an application fits in the larger context of data collection. A sneak peak at the completed project, including every source file, provides a road map to where the tutorial is taking you. In cooking-show fashion, you build the application from the ground up with each Java class carefully introduced and related to other aspects of the application, most notably the data model upon which this forms engine is constructed. To conclude, you save form data to the server and look briefly at the server side of the application.

Prerequisites
Table 1 shows the tools required for this project. Table 1. The necessary tools for the job
Tool Eclipse and ADT Android SDK Web server Comment Primary code editor and Android Developer Tools Plugin. Android Software Developer Kit. Any variety that supports PHP. You can easily port the script to another server environment.

I created the code samples for this tutorial on a MacBook with Eclipse 3.4.2 and Android SDK version 8, which supports the Android release labeled 2.2. The tutorial code is not leveraging any specific features of this SDK and the application should run just fine in Android versions dating back as far as 1.5. See Resources for links to all the tools.

Section 2. Data collection


Let's begin with a short discussion about data collection, and how it can be easy to implement when using an Android mobile device.

An Android data collection framework


Collecting data is a task that pre-dates the computer era. Computers have become a daily staple and have revolutionized the way you think about, find, and consume information. Companies with billion dollar market-caps exist thanks to their effectiveness in storing, retrieving, and managing vast amounts of information. The
Build dynamic user interfaces with Android and XML Page 2 of 42

ibm.com/developerWorks/

developerWorks

databases in use today are fed by systems of varying architectures including the main frame, client server, web applications, and now mobile applications. Physical inventory and cycle counting applications were some of the early practical applications of mobile computing. These applications were often batch data collection, where the hardware required a docking station to upload the collected information. The market for mobile applications has come a long way since those early days, and wireless connectivity and devices are nearly ubiquitous in many cultures and markets, invading virtually every aspect of daily life. While the means of collecting data may have become more mobile, the core aspect of data collection has not changed significantly. The user must be presented a collection of questions and have a simple means of responding. This tutorial demonstrates the construction of a simple data collection framework for Androidpowered mobile phones, leveraging a dynamic metadata structure enabled by XML.

Section 3. The application architecture


Before diving into the code, examine the application setting from a very high level.

Forms Engine at a glance


Take a walk through all of the aspects of the Forms Engine application. Figure 1 depicts the relation of the application to one or more servers that provide data entry forms of varying content. Figure 1. Application architecture

Build dynamic user interfaces with Android and XML

Page 3 of 42

developerWorks

ibm.com/developerWorks/

In Figure 1, Form 1 provides registration for Robotics Competition and Form 2 asks the user for information about his auto maintenance habit. Using HTTP(S), the forms and Android application communicate to: Download the form data. Present form data to the user and optional collect device-specific data, such as camera images, sound recordings, GPS location, or compass readings. Collect user-supplied data. Submit data to the appropriate server. The server side of this tutorial is implemented as a pair of files: an XML document describing the form and a PHP document responsible for recording the submission of the form. The Android application is a native application written in Java code using the Android SDK and coded in Eclipse. Table 2 shows the application source files for the complete application. You can download the zipped file containing all of these source files (see Downloads). You will go through each of these files in detail in this tutorial. Table 2. The required application source files
Filename XmlGui.java XmlGuiForm.java XmlGuiFormField.java XmlGuiEditBox.java XmlGuiPickOne.java RunForm.java main.xml AndroidManifest.xml xmlgui1.xml xmlgui1-post.php xmlgui2.xml Comment Entry point for Android Activity High level data model and methods for a form Represents a form field and holds the metadata for each field of a form Implements a text box type user interface element Implements a drop-down list type user interface element Processes a form, using the above classes Home page of application user interface Deployment descriptor for the Android application Sample form for collecting Robotics competition registration PHP script for processing form submissions Sample form for taking survey of automotive maintenance habits

Figure 2 shows the project structure in Eclipse for the complete application as it will look at the end of this tutorial. (View a text-only version of Figure 2.)

Build dynamic user interfaces with Android and XML

Page 4 of 42

ibm.com/developerWorks/

developerWorks

Figure 2. Project in Eclipse

If you do not have a working Android development environment, now is a great time to install the Android tools. For more information on how to setup an Android development environment, look in Resources for links to both of the required tools, plus some introductory articles and tutorials on developing applications for Android. Having a familiarity with Android is helpful in understanding this tutorial. Now that you have an overview of the architecture and the application, you can get started!

Section 4. The project and data model


We are now ready to start the Android project in Eclipse, creating the data model and the class that will allow you to store and manage metadata for the Forms Engine application.

Creating the project


Creating Android applications starts in the familiar place: Open Eclipse and select File > New as in Figure 3.
Build dynamic user interfaces with Android and XML Page 5 of 42

developerWorks Figure 3. Creating a new Android application

ibm.com/developerWorks/

This step launches the Eclipse New project wizard. Select Android Project (the specialized Java environment for Android). Be sure to give the project a valid identifier (I used XMLGUI). To match the solution as described in this tutorial, under Properties, specify XML GUI as the application name and com.msi.ibm as the package name. Select the Create Activity check box and specify XmlGui for the Activity name as in Figure 4.

Build dynamic user interfaces with Android and XML

Page 6 of 42

ibm.com/developerWorks/

developerWorks

Figure 4. Setting up a new project

Once the project is created, it should look very similar to the image in Figure 5. (View a text-only version of Figure 5.)
Build dynamic user interfaces with Android and XML Page 7 of 42

developerWorks

ibm.com/developerWorks/

Figure 5. Android project directly upon completion of the new project wizard

With the project now created, it is good practice to ensure that the application builds cleanly and runs in the Android Emulator. Note that sometimes the application does not build until you edit and save the Java source file. This causes the Android SDK tools to automatically generate the files in the gen folder. This causes the files in the gen folder to be automatically generated by the Android SDK tools. You can test the application if there are no entries showing up in the Problems tab of the Eclipse environment. To test the application, create a Run Configuration, as in Figure 6. In the Android Application list, select XmlGui. Ensure the following values are present: XmlGui in the Name field, XMLGUI in the Project field, and com.msi.ibm.XmlGui in the Launch field. Click Run.

Build dynamic user interfaces with Android and XML

Page 8 of 42

ibm.com/developerWorks/

developerWorks

Figure 6. Run Configuration setup

Now that the project is created, is configured, and starts properly in the Android emulator, it is time to create the XML driven data collection tool for Android.

The data model


The nuts and bolts of this application require it to present input elements to a user, collect data, validate the data, and then submit that data to a specified server location. It is worth noting that this application is set up for new records only. There are no provisions to look up an existing record for editing or deleting. To provide enough direction to the application on how to present the data entry forms, a set of information (commonly referred to as metadata) is required. Metadata is data about data. In general terms, this application must understand a few data elements including: Form NameHuman readable name of the form Form IdentifierUnique identifier for this metadata collection Submission URLWhere to send the collected data One or more fieldsThese can be text, numeric, or "choose from a list" kind of fields

Virtually all kinds of questions map to one of these three types of user interface elements. For example, you can implement a check box as a Yes or No choice field.
Build dynamic user interfaces with Android and XML Page 9 of 42

developerWorks

ibm.com/developerWorks/

You can implement multi-select as multiple choice fields. Of course, you can extend the code shown in this tutorial as desired. For your application, the usage scenario is as follows: You are at an event where you can register for one or more activities. You could fill out a piece of paper, or you could wait until you get home and hope that you remember to sign onto the organization's website to register. In this case, you will assume that a user will fill out a simple form on the spot from his phone by pulling up a dynamic form on an Android device, providing the entrant's first name, last name, gender, and age. Listing 1 shows the contents of xmlgui1.xml, which represents a registration form for a Robotics club event. Listing 1. xmlgui1.xml
<?xml version="1.0" encoding="utf-8"?> <xmlgui> <form id="1" name="Robotics Club Registration" submitTo="http://serverurl/xmlgui1-post.php" > <field name="fname" label="First Name" type="text" required="Y" options=""/> <field name="lname" label="Last Name" type="text" required="Y" options=""/> <field name="gender" label="Gender" type="choice" required="Y" options="Male|Female"/> <field name="age" label="Age on 15 Oct. 2010" type="numeric" required="N" options=""/> </form> </xmlgui>

Note the following things about this XML document: The XML is very simple to parse thanks to extensive use of element attributes. This approach is used because it makes extracting the data easier than multiple child elements and tags. Using attributes in this manner also keeps the download size small and aids in keeping the parse time low. The submitTo attribute tells the application where to send the data once it is collected. Each field element provides attributes for both a field name and a label. While these values are related, you want to keep the value of each name attribute unique from the other name attribute values so the receiving application can properly parse and process them. You must also provide an informative label value to the user as a cue to what kind of data should go into a particular field. You can readily expand this approach to include default values for each field, a regex expression for validation, or a link for more information about a particular field. The options field is used as a delimited list for the choice field. With a basic familiarity with the data model, now look at the code responsible for turning this XML data into a useful application.

Representing the data


Parsing the data is a rather mechanical exercise shown later in this tutorial. Before examining the parsing process, the application needs some place to store and
Build dynamic user interfaces with Android and XML Page 10 of 42

ibm.com/developerWorks/

developerWorks

manage the metadata in memory. For this purpose, you have two Java classes, one for the form and one to represent the form field. Start by looking at XmlGuiForm.java in Listing 2. Listing 2. XmlGuiForm.java
package com.msi.ibm; import java.util.Vector; import java.util.ListIterator; import java.net.URLEncoder; public class XmlGuiForm { private String formNumber; private String formName; private String submitTo; public Vector<XmlGuiFormField> fields; public XmlGuiForm() { this.fields = new Vector<XmlGuiFormField>(); formNumber = ""; formName = ""; submitTo = "loopback"; // do nothing but display the results } // getters & setters public String getFormNumber() { return formNumber; } public void setFormNumber(String formNumber) { this.formNumber = formNumber; } public String getFormName() { return formName; } public void setFormName(String formName) { this.formName = formName; } public String getSubmitTo() { return submitTo; } public void setSubmitTo(String submitTo) { this.submitTo = submitTo; } public Vector<XmlGuiFormField> getFields() { return fields; } public void setFields(Vector<XmlGuiFormField> fields) { this.fields = fields; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("XmlGuiForm:\n"); sb.append("Form Number: " + this.formNumber + "\n"); sb.append("Form Name: " + this.formName + "\n"); sb.append("Submit To: " + this.submitTo + "\n");

Build dynamic user interfaces with Android and XML

Page 11 of 42

developerWorks

ibm.com/developerWorks/

if (this.fields == null) return sb.toString(); ListIterator<XmlGuiFormField> li = this.fields.listIterator(); while (li.hasNext()) { sb.append(li.next().toString()); } return sb.toString(); } public String getFormattedResults() { StringBuilder sb = new StringBuilder(); sb.append("Results:\n"); if (this.fields == null) return sb.toString(); ListIterator<XmlGuiFormField> li = this.fields.listIterator(); while (li.hasNext()) { sb.append(li.next().getFormattedResult() + "\n"); } return sb.toString(); } public String getFormEncodedData() { try { int i = 0; StringBuilder sb = new StringBuilder(); sb.append("Results:\n"); if (this.fields == null) return sb.toString(); ListIterator<XmlGuiFormField> li = this.fields.listIterator(); while (li.hasNext()) { if (i != 0) sb.append("&"); XmlGuiFormField thisField = li.next(); sb.append(thisField.name + "="); String encstring = new String(); URLEncoder.encode((String) thisField.getData(),encstring); sb.append(encstring); } return sb.toString(); } catch (Exception e) { return "ErrorEncoding"; } } }

Here are some important items to note about the XmlGuiForm class. 1. There are four member variables: formNumber: This is the unique identifier for the server side form distribution mechanism. formName: This becomes the title of the form, providing context and confirmation for the user. submitTo: This is the URL for the application to submit the data entered (after validation). Alternatively this value can be a loopback. In the loopback scenario, the data is displayed to the user rather than submitted to the server. This is useful for testing purposes. fields: This is a Vector class templated to hold the form's field data. Listing 3 shows the details for XmlGuiFormField.java.
Build dynamic user interfaces with Android and XML Page 12 of 42

ibm.com/developerWorks/

developerWorks

2. A series of getters and setters for each of these variables. 3. The toString() and getFormattedResults() methods are responsible for generating human readable summarizations of the XmlGuiForm class. 4. The getFormEncodedData() method is used when preparing data for submission to the URL indicated in the submitTo attribute. 5. Rather than using strictly concatenated java.lang.String classes, the code employs a StringBuilder as a more memory efficient means of building the desired data strings. 6. The URLEncoder class is leveraged to prepare data for submission to the server. This makes the data look like it was actually created by a traditional HTML form. 7. Some potential expansions of this application include: Local storage or caching of metadata to make repetitive tasks run more quickly. Local storage to record data over a period of time prior to submission. GPS recordingstamp each record with location data. Now look at the construction of the XmlGuiFormField class in Listing 3. Listing 3. XmlGuiFormField.java
package com.msi.ibm; // class to handle each individual form public class XmlGuiFormField { String name; String label; String type; boolean required; String options; Object obj; // holds the ui implementation // or the EditText for example // getters & setters public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getType() { return type; } public void setType(String type) { this.type = type; } public boolean isRequired() { return required; } public void setRequired(boolean required) { this.required = required; } public String getOptions() { return options; }

Build dynamic user interfaces with Android and XML

Page 13 of 42

developerWorks
public void setOptions(String options) { this.options = options; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Field Name: " + this.name + "\n"); sb.append("Field Label: " + this.label + "\n"); sb.append("Field Type: " + this.type + "\n"); sb.append("Required? : " + this.required + "\n"); sb.append("Options : " + this.options + "\n"); sb.append("Value : " + (String) this.getData() + "\n"); return sb.toString(); } public String getFormattedResult() { return this.name + "= [" + (String) this.getData() + "]"; } public Object getData() { if (type.equals("text") || type.equals("numeric")) { if (obj != null) { XmlGuiEditBox b = (XmlGuiEditBox) obj; return b.getValue(); } } if (type.equals("choice")) { if (obj != null) { XmlGuiPickOne po = (XmlGuiPickOne) obj; return po.getValue(); } } // You could add logic for other UI elements here return null; } }

ibm.com/developerWorks/

Look more closely at the XmlGuiFormField class. There are six class level members: 1. name holds the name of the fieldthis is the field name of the data value, analogous to a form field name in HTML or a database column name. 2. label holds the description of the field or the value shown to the user. 3. type indicates the flavor of user interface field to construct. text means this is field is implemented with an EditText field for alphanumeric entries. This is the most common value. numeric is also an EditText, but it is constrained to a numeric entry value. choice makes the field a drop-down list. 4. required is a Boolean value marking the field as required or not. If the field is required and not populated, an error message is displayed to the user when the user attempts to submit the form.
Build dynamic user interfaces with Android and XML Page 14 of 42

ibm.com/developerWorks/

developerWorks

5. options is a string value used to convey the list of available selections for a choice field. This field is available for other fields to be used as perhaps a regex expression for validation or it can be overridden to specify a default value. 6. obj represents the user interface widget. For example, this variable holds an EditText for a text or numeric field. For a choice field, the obj member contains a spinner widget. This approach is further explained later in this tutorial. As expected, these variables have a number of getters and setters. The toString() and getFormattedResult() methods both leverage the getData() method, explained next. In the XmlGuiFormField class, you need to manage more than one type of data, so the code needs to be explicit about how data is stored and accessed. The getData() method examines the type field and performs a type-cast on the obj field to properly interact with the stored object. If you wish to add new field types to this framework, you can expand the getData() method to support the new field type (see the comment near the end of Listing 3. You now have a way to store and manage metadata. It is time to look at the application in action and then tie the various pieces together.

Section 5. Assemble a user interface


Start by creating a form for a mobile user to enter data into.

Taking it from the top


The entry point of the application resides in XmlGui.java, as in Listing 4. Listing 4. The application entry point: XmlGui
package com.msi.ibm; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Button; import android.widget.TextView; import android.content.Intent; import android.util.Log; public class XmlGui extends Activity { final String tag = XmlGui.class.getName(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btnRunForm = (Button) this.findViewById(R.id.btnRunForm); btnRunForm.setOnClickListener(new Button.OnClickListener() { public void onClick(View v)

Build dynamic user interfaces with Android and XML

Page 15 of 42

developerWorks
{

ibm.com/developerWorks/

EditText formNumber = (EditText) findViewById(R.id.formNumber); Log.i(tag,"Attempting to process Form # [" + formNumber.getText().toString() + "]"); Intent newFormInfo = new Intent(XmlGui.this,RunForm.class); newFormInfo.putExtra("formNumber", formNumber.getText().toString()); startActivity(newFormInfo); } }); } }

The user interface for the main Activity is very simple, consisting of only: A label (TextView) An entry box (EditText) A button (Button) The code for XmlGui Activity is very standard in nature. You inflate a layout created at design time and then define and create a button handler to implement the desired functionality (which is explained further below). You define the user interface in the file main.xml (found in the layout subfolder of the res folder). Listing 5 shows main.xml. Listing 5. main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/Title" /> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" > <EditText android:layout_width="100px" android:layout_height="wrap_content" android:text="1" android:id="@+id/formNumber" android:numeric="integer"/> <Button android:text="Run Form" android:id="@+id/btnRunForm" android:layout_width="wrap_content" android:layout_height="wrap_content"> </Button> </LinearLayout> </LinearLayout>

Build dynamic user interfaces with Android and XML

Page 16 of 42

ibm.com/developerWorks/

developerWorks

As a reminder, you can modify layouts by editing the XML directly or by using the Layout tool contained in the Android Developer Tools as in Figure 7. Figure 7. Layout tool

To run the application, click on the home screen icon that launches the XmlGui Activity seen in Figure 8.

Build dynamic user interfaces with Android and XML

Page 17 of 42

developerWorks Figure 8. Application in action

ibm.com/developerWorks/

When the user enters a form number and taps the Run Form button, a series of events is kicked off. Let's go through the onClick() method, line by line. Recall that the onClick() method is in the XmlGui class in Listing 4. You get a reference to the EditText field named formNumber. The R.id.formNumber enumeration is automatically generated by the Android build tools whenever the main.xml file is saved:
EditText formNumber = (EditText) findViewById(R.id.formNumber);

Next, you put a line into the log. You can see the output of this log in the Dalvik Debug Monitor Service (DDMS) perspective in Eclipse, provided by the Android Developer Tools plugin:
Log.i(tag,"Attempting to process Form # [" + formNumber.getText().toString() + "]");

The actual implementation of the Form Engine is provided in the RunForm class, which extends the Activity class. To launch this Activity, create an Intent, explicitly identifying the RunForm class:
Intent newFormInfo = new Intent(XmlGui.this,RunForm.class);

Build dynamic user interfaces with Android and XML

Page 18 of 42

ibm.com/developerWorks/

developerWorks

Not only do you want to launch the RunForm Activity, but you also want to specify which form to display. To do this, add the form number to the Intent through the putExtra method:
newFormInfo.putExtra("formNumber", formNumber.getText().toString());

This value is extracted by the RunForm class, shown later. Now that you have set up the Intent, you launch the Activity with a call to startActivity:
startActivity(newFormInfo);

With your application, the user enters the form number and clicks the Run Form button. This triggers the events described above, causing the RunForm class to process the request. Entering a form number is really just a test tool for the purposes of this tutorial. There are other means by which this triggering event can take place. More practical examples include customized links from a web page, a message pushed through Short Message Service (SMS), a location-based trigger based on proximity, or even a scanned QR code (Quick Response code).

Running the form


The RunForm class is the choreographer for this application. It is launched with a form number to process. Now examine the onCreate() method in Listing 6. Listing 6. The onCreate() method
public class RunForm extends Activity { /** Called when the activity is first created. */ String tag = RunForm.class.getName(); XmlGuiForm theForm; ProgressDialog progressDialog; Handler progressHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String formNumber = ""; Intent startingIntent = getIntent(); if(startingIntent == null) { Log.e(tag,"No Intent? We're not supposed to be here..."); finish(); return; } formNumber = startingIntent.getStringExtra("formNumber"); Log.i(tag,"Running Form [" + formNumber + "]"); if (GetFormData(formNumber)) { DisplayForm(); } else { Log.e(tag,"Couldn't parse the Form."); AlertDialog.Builder bd = new AlertDialog.Builder(this); AlertDialog ad = bd.create(); ad.setTitle("Error");

Build dynamic user interfaces with Android and XML

Page 19 of 42

developerWorks
ad.setMessage("Could not parse the Form data"); ad.show(); } } // other methods omitted and shown later }

ibm.com/developerWorks/

As seen in the code in Listing 6, first you extract the formNumber from the Intent that triggered the Activity. Without a form number to process, this Activity has nothing to perform. Once you extract the value, the next requirement is to connect to the server to download the form specifications. (Note that an enhancement of this approach might be to look for this form's metadata in a local cache prior to fetching the data.) Listing 7 shows the GetFormData() method. Listing 7. The GetFormData() method
private boolean GetFormData(String formNumber) { try { Log.i(tag,"ProcessForm"); URL url = new URL("http://www.example.com/xmlgui" + formNumber + ".xml"); Log.i(tag,url.toString()); InputStream is = url.openConnection().getInputStream(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder db = factory.newDocumentBuilder(); Document dom = db.parse(is); Element root = dom.getDocumentElement(); NodeList forms = root.getElementsByTagName("form"); if (forms.getLength() < 1) { // nothing here?? Log.e(tag,"No form, let's bail"); return false; } Node form = forms.item(0); theForm = new XmlGuiForm(); // process form level NamedNodeMap map = form.getAttributes(); theForm.setFormNumber(map.getNamedItem("id").getNodeValue()); theForm.setFormName(map.getNamedItem("name").getNodeValue()); if (map.getNamedItem("submitTo") != null) theForm.setSubmitTo(map.getNamedItem("submitTo").getNodeValue()); else theForm.setSubmitTo("loopback"); // now process the fields NodeList fields = root.getElementsByTagName("field"); for (int i=0;i<fields.getLength();i++) { Node fieldNode = fields.item(i); NamedNodeMap attr = fieldNode.getAttributes(); XmlGuiFormField tempField = new XmlGuiFormField(); tempField.setName(attr.getNamedItem("name").getNodeValue()); tempField.setLabel(attr.getNamedItem("label").getNodeValue()); tempField.setType(attr.getNamedItem("type").getNodeValue()); if (attr.getNamedItem("required").getNodeValue().equals("Y")) tempField.setRequired(true); else tempField.setRequired(false); tempField.setOptions(attr.getNamedItem("options").getNodeValue()); theForm.getFields().add(tempField); }

Build dynamic user interfaces with Android and XML

Page 20 of 42

ibm.com/developerWorks/

developerWorks

Log.i(tag,theForm.toString()); return true; } catch (Exception e) { Log.e(tag,"Error occurred in ProcessForm:" + e.getMessage()); e.printStackTrace(); return false; } }

This code is responsible for taking data from a metadata repository, in this case by downloading an XML file from a Webserver:
URL url = new URL("http://10.211.55.2/~fableson/xmlgui" + formNumber + ".xml");

Manipulate the XML data through a DOM parser, to extract the form and field elements plus attributes and store them in instances of the XmlGuiForm and XmlGuiFormField classes respectively. The bulk of this method is dedicated to the parsing and populating tasks. Two main approaches to XML parsing are DOM and SAX. The DOM parser works by parsing a document into memory and then the application walks a Document Object Model tree to gain access to various elements of data contained in the XML. You also could also use the SAX parser model here because you build your own representation of the document by populating the two classes. The advantage of the DOM approach for this application is that it is somewhat procedural and easy to follow the code, whereas the SAX approach requires callback functions where only the desired data is stored. The complexity of the code written by the developer to implement the SAX callback functions can be noticeably higher than the DOM approach in some instances. Because the XML data is fully parsed in the DOM approach, it is a bit more memory intensive. For your purposes in this application, the simplicity and easy-to-follow nature of DOM was a bigger driver than memory management as the metadata form is quite small. See Resources for an excellent reference on coding XML parsers in Android. You have transformed the XML metadata form to Java class instances. It is now time to display the form to gather data from the user.

Section 6. Gather user data


Now that you've created the main Activity screen layout, you can create user interface forms for collecting data. Here you'll create a Robotics Club Registration form and an Auto Maintenance survey form.
Build dynamic user interfaces with Android and XML Page 21 of 42

developerWorks

ibm.com/developerWorks/

Using the metadata


This application hinges upon the ability of Android programmers to dynamically manipulate the user interface. Earlier in the tutorial, you examined the main.xml file, the file that defines the screen layout of the XmlGui class (the main Activity). This application would be virtually impossible in its current form if you had to always define user interface elements at design or compile time. Thankfully, you are not constrained in that manner. The DisplayForm() method is responsible for converting the metadata into user interface elements for the purposes of collecting data. The code is essentially broken into two main functional areas: the layout of the user interface elements and then the handling of the submit button. First, examine the layout logic. This is the code that turns the XmlGuiForm object into a real on-the-screen form. Listing 8 shows this code. Listing 8. The layout logic
private boolean DisplayForm() { try { ScrollView sv = new ScrollView(this); final LinearLayout ll = new LinearLayout(this); sv.addView(ll); ll.setOrientation(android.widget.LinearLayout.VERTICAL); // walk through the form elements and dynamically create them, // leveraging the mini library of tools. int i; for (i=0;i<theForm.fields.size();i++) { if (theForm.fields.elementAt(i).getType().equals("text")) { theForm.fields.elementAt(i).obj = new XmlGuiEditBox(this,(theForm.fields.elementAt(i).isRequired() ? "*" : "") + theForm.fields.elementAt(i).getLabel(),""); ll.addView((View) theForm.fields.elementAt(i).obj); } if (theForm.fields.elementAt(i).getType().equals("numeric")) { theForm.fields.elementAt(i).obj = new XmlGuiEditBox(this,(theForm.fields.elementAt(i).isRequired() ? "*" : "") + theForm.fields.elementAt(i).getLabel(),""); ((XmlGuiEditBox)theForm.fields.elementAt(i).obj).makeNumeric(); ll.addView((View) theForm.fields.elementAt(i).obj); } if (theForm.fields.elementAt(i).getType().equals("choice")) { theForm.fields.elementAt(i).obj = new XmlGuiPickOne(this,(theForm.fields.elementAt(i).isRequired() ? "*" : "") + theForm.fields.elementAt(i).getLabel(), theForm.fields.elementAt(i).getOptions()); ll.addView((View) theForm.fields.elementAt(i).obj); } } Button btn = new Button(this); btn.setLayoutParams(new LayoutParams (ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams. WRAP_CONTENT));

Build dynamic user interfaces with Android and XML

Page 22 of 42

ibm.com/developerWorks/

developerWorks

ll.addView(btn); btn.setText("Submit"); btn.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // check if this form is Valid if (!CheckForm()) { AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Error"); ad.setMessage("Please enter all required (*) fields"); ad.show(); return; } if (theForm.getSubmitTo().equals("loopback")) { // just display the results to the screen String formResults = theForm.getFormattedResults(); Log.i(tag,formResults); AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Results"); ad.setMessage(formResults); ad.show(); return; } else { if (!SubmitForm()) { AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Error"); ad.setMessage("Error submitting form"); ad.show(); return; } } } } ); setContentView(sv); setTitle(theForm.getFormName()); return true; } catch (Exception e) { Log.e(tag,"Error Displaying Form"); return false; } }

You must anticipate the availability of more fields than can fit on a single screen, so use a ScrollView as the parent view or container. Within that ScrollView you employ a vertical LinearLayout to organize the various user interface widgets into a vertical column. The approach is pretty simple: You enumerate through the list of XmlGuiFormField objects contained within the fields member of the XmlGuiForm instance.

Build dynamic user interfaces with Android and XML

Page 23 of 42

developerWorks

ibm.com/developerWorks/

Depending on the type of field requested, a different user interface element is instantiated and added to the LinearLayout. You will examine the different UI widgets momentarily. Once the UI elements are created and added to the linear layout, you assign the entire ScrollView instance to the content of this screen and assign the form name as the title of the screen. Figure 9 shows a Robotics club registration screen ready for user input. This form is the result of processing the XML data found back in Listing 1. Figure 9. Robotics registration form in action

Let's have a look at the different custom user interface widgets created for this application. Recall that three types of data entry fields are defined for this application: text, numeric, and choice. These three types are implemented through two different custom widgets: XmlGuiEditBox and XmlGuiPickOne. The text and numeric values are so similar you can leverage the same EditView approach, but with different input filters to switch between alpha-numeric and numeric only. Listing 9 shows the code for the XmlGuiEditBox class. Listing 9. The XmlGuiEditBox class
package com.msi.ibm; import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup;

Build dynamic user interfaces with Android and XML

Page 24 of 42

ibm.com/developerWorks/

developerWorks

import import import import

android.widget.LinearLayout; android.widget.TextView; android.widget.EditText; android.text.method.DigitsKeyListener;

public class XmlGuiEditBox extends LinearLayout { TextView label; EditText txtBox; public XmlGuiEditBox(Context context,String labelText,String initialText) { super(context); label = new TextView(context); label.setText(labelText); txtBox = new EditText(context); txtBox.setText(initialText); txtBox.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams .FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT)); this.addView(label); this.addView(txtBox); } public XmlGuiEditBox(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public void makeNumeric() { DigitsKeyListener dkl = new DigitsKeyListener(true,true); txtBox.setKeyListener(dkl); } public String getValue() { return txtBox.getText().toString(); } public void setValue(String v) { txtBox.setText(v); } }

The XmlGuiEditBox class extends the LinearLayout class and contains both a textual label to describe the requested input and an EditText to actually collect the entered data. All of the object initialization is done in the constructor. This may be considered bad form, but this is an exercise left to you if you're uncomfortable with that approach. There are three other methods to discuss. The getValue() and setValue() methods do just what you would think. They are the getter and setter for interacting with the EditText field. The third method, makeNumeric() is only called when setting up a form field type of numeric. An instance of the DigitsKeyListener is employed to filter out any nonnumeric keys. The other nice thing that you get for free is the proper keyboard is shown depending on which type of XmlGuiEditBox is in usewith or without the numeric setting. Figure 10 shows the form in action with an alpha keyboard shown because the Last Name field is set for alpha entry, in other words text.
Build dynamic user interfaces with Android and XML Page 25 of 42

developerWorks Figure 10. Alphanumeric key entry

ibm.com/developerWorks/

Figure 11 shows the numeric keyboard in use because the age field is set for the data type of numeric.

Build dynamic user interfaces with Android and XML

Page 26 of 42

ibm.com/developerWorks/

developerWorks

Figure 11. Numeric keyboard

The choice field, implemented in the user interface through the XmlGuiPickOne class, is a little different. The choice field is implemented as an Android Spinner widget. This user interface element is analogous to a drop-down list box in other programming environments, where the user must select from one of the existing choices. Figure 12 shows three instances XmlGuiPickOne widget.

Build dynamic user interfaces with Android and XML

Page 27 of 42

developerWorks

ibm.com/developerWorks/

Figure 12. Auto maintenance survey with three XmlGuiPickOne instances

In this example, the data being collected is for statistical purposes, so normalizing the possible entries makes the data processing cleaner than dealing with free text entry fields. Of course, you can define the State field as a choice field if you wanted to constrain the survey to a particular geographical region. Listing 10 shows the code for the XmlGuiPickOne class. Listing 10. The XmlGuiPickOne class
package com.msi.ibm; import import import import import import android.content.Context; android.util.AttributeSet; android.widget.LinearLayout; android.widget.TextView; android.widget.Spinner; android.widget.ArrayAdapter;

public class XmlGuiPickOne extends LinearLayout { String tag = XmlGuiPickOne.class.getName(); TextView label; ArrayAdapter<String> aa; Spinner spinner; public XmlGuiPickOne(Context context,String labelText,String options) { super(context); label = new TextView(context); label.setText(labelText); spinner = new Spinner(context); String []opts = options.split("\\|"); aa = new ArrayAdapter<String>( context, android.R.layout.simple_spinner_item,opts);

Build dynamic user interfaces with Android and XML

Page 28 of 42

ibm.com/developerWorks/

developerWorks

spinner.setAdapter(aa); this.addView(label); this.addView(spinner); } public XmlGuiPickOne(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public String getValue() { return (String) spinner.getSelectedItem().toString(); } }

This class looks very similar to the XmlGuiEditBox class. The major difference is that a Spinner control is employed rather than an EditText control. Also, note that this class only implements the getValue() method. An obvious enhancement to this class is permit the user to specify a default value. Note the use of the options member to populate the list of choices. In this code, the String containing the available choices is split into an array using a regex expression and then passed to an instance of an ArrayAdapter. The constant android.R.layout.simple_spinner_item is built-in to Android. It was not supplied in the tutorial application code. Once the adapter is set up, you assign it to the Spinner. Figure 13 shows the list of choices displayed on the screen, prompting the user for the typical number of miles between oil changes.

Build dynamic user interfaces with Android and XML

Page 29 of 42

developerWorks Figure 13. XmlGuiPickOne asking about oil changes

ibm.com/developerWorks/

Now that the user can enter data into the form, it is time to validate and submit the data.

Section 7. Save and submit data


You must now create a way for users to save the data by validating it and submitting it to a server.

Saving data
It is time to jump back into the DisplayForm() method of the RunForm class. Recall that the first portion of this method is responsible for the drawing of the form. Next, you will examine the onClick() handler of the submit button, in Listing 11. Listing 11. The onClick() handler
btn.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // check if this form is Valid if (!CheckForm()) { AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Error"); ad.setMessage("Please enter all required (*) fields"); ad.show(); return;

Build dynamic user interfaces with Android and XML

Page 30 of 42

ibm.com/developerWorks/

developerWorks

} if (theForm.getSubmitTo().equals("loopback")) { // just display the results to the screen String formResults = theForm.getFormattedResults(); Log.i(tag,formResults); AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Results"); ad.setMessage(formResults); ad.show(); return; } else { if (!SubmitForm()) { AlertDialog.Builder bd = new AlertDialog.Builder(ll.getContext()); AlertDialog ad = bd.create(); ad.setTitle("Error"); ad.setMessage("Error submitting form"); ad.show(); return; } } } } );

When the submit button is selected by the user, the form entries are checked to make sure that all of the required fields are populated. If not, an AlertDialog reminds the user to populate all of the fields. Assuming the data has been entered in a satisfactory manner, it is time to submit the data. The process of submitting the data falls into one of two camps for this tutorial application. If the submitTo field of the form has been set to the value of loopback, the values are simply echoed to the screen. This is useful for testing purposes. Once you are satisfied that the form tool is collecting data properly, it is time to point it to a server page which is responsible for recording the entries. Listing 12 shows the CheckForm() method. This code is rather straight-forward. Each field is checked to see if it is required. If the field is required but the user has not provided the information, a flag is set. You could enhance this to provide more specific feedback to the user. Listing 12. The CheckForm() method
private boolean CheckForm() { try { int i; boolean good = true; for (i=0;i<theForm.fields.size();i++) { String fieldValue = (String) theForm.fields.elementAt(i).getData(); Log.i(tag,theForm.fields.elementAt(i) .getName() + " is [" + fieldValue + "]"); if (theForm.fields.elementAt(i).isRequired()) { if (fieldValue == null) { good = false; } else { if (fieldValue.trim().length() == 0) {

Build dynamic user interfaces with Android and XML

Page 31 of 42

developerWorks
good = false; } } } } return good; } catch(Exception e) { Log.e(tag,"Error in CheckForm()::" + e.getMessage()); e.printStackTrace(); return false; } }

ibm.com/developerWorks/

Now it is time to submit the collected data to the server. Examine the SubmitForm() method in Listing 13. Listing 13. The SubmitForm() method
private boolean SubmitForm() { try { boolean ok = true; this.progressDialog = ProgressDialog.show(this, theForm.getFormName(), "Saving Form Data", true,false); this.progressHandler = new Handler() { @Override public void handleMessage(Message msg) { // process incoming messages here switch (msg.what) { case 0: // update progress bar progressDialog.setMessage("" + (String) msg.obj); break; case 1: progressDialog.cancel(); finish(); break; case 2: progressDialog.cancel(); break; } super.handleMessage(msg); } }; Thread workthread = new Thread(new TransmitFormData(theForm)); workthread.start(); return ok; } catch (Exception e) { Log.e(tag,"Error in SubmitForm()::" + e.getMessage()); e.printStackTrace(); // tell user that the submission failed.... Message msg = new Message(); msg.what = 1; this.progressHandler.sendMessage(msg); return false; } }

Build dynamic user interfaces with Android and XML

Page 32 of 42

ibm.com/developerWorks/

developerWorks

First, you set up an instance of the android.os.Handler class. The Handler class is helpful when an application needs to share data with different threads. Another important item to note in the SubmitForm() method is the use of a ProgressDialog. Note that the ProgressDialog and Handler are defined as class level variables in Listing 14. Listing 14. The ProgressDialog and Handler
public class RunForm extends Activity { /** Called when the activity is first created. */ String tag = RunForm.class.getName(); XmlGuiForm theForm; ProgressDialog progressDialog; Handler progressHandler; ... }

You don't want to unnecessarily block the application while communicating with the server, so you employ a background Thread to communicate, but you rely on the Handler to receive notifications from the communications thread in order to provide feedback to the user. Note that only the main thread is supposed to interact with the user interface. An alternative to the separate thread approach is the AsyncTask class found in the android.os package. As the application connects to the server to transfer the data, it has the opportunity to inform the user of the status of the operation, which is of course good practice. Figure 14 shows the ProgressDialog in action.

Build dynamic user interfaces with Android and XML

Page 33 of 42

developerWorks Figure 14. The ProgressDialog

ibm.com/developerWorks/

The actual server communications code is found in Listing 15, in the TransmitFormData() class, which implements the Runnable interface. Listing 15. The TransmitFormData class
private class TransmitFormData implements Runnable { XmlGuiForm _form; Message msg; TransmitFormData(XmlGuiForm form) { this._form = form; } public void run() { try { msg = new Message(); msg.what = 0; msg.obj = ("Connecting to Server"); progressHandler.sendMessage(msg); URL url = new URL(_form.getSubmitTo()); URLConnection conn = url.openConnection(); conn.setDoOutput(true); BufferedOutputStream wr = new BufferedOutputStream (conn.getOutputStream()); String data = _form.getFormEncodedData(); wr.write(data.getBytes()); wr.flush(); wr.close(); msg = new Message(); msg.what = 0;

Build dynamic user interfaces with Android and XML

Page 34 of 42

ibm.com/developerWorks/

developerWorks

msg.obj = ("Data Sent"); progressHandler.sendMessage(msg); // Get the response BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = ""; Boolean bSuccess = false; while ((line = rd.readLine()) != null) { if (line.indexOf("SUCCESS") != -1) { bSuccess = true; } // Process line... Log.v(tag, line); } wr.close(); rd.close(); if (bSuccess) { msg = new Message(); msg.what = 0; msg.obj = ("Form Submitted Successfully"); progressHandler.sendMessage(msg); msg = new Message(); msg.what = 1; progressHandler.sendMessage(msg); return; } } catch (Exception e) { Log.d(tag, "Failed to send form data: " + e.getMessage()); msg = new Message(); msg.what = 0; msg.obj = ("Error Sending Form Data"); progressHandler.sendMessage(msg); } msg = new Message(); msg.what = 2; progressHandler.sendMessage(msg); } }

The TransmitFormData class is responsible for connecting to the server listed in the submitTo member of the XmlGuiForm instance (as taken from the metadata). It periodically updates the main application thread by sending an instance of a Message class to the handler through the sendMessage() method. Two members are populated on the Message class: The what value acts as a high-level switch informing the Handler what it should do with the message. The obj value specifies an optional java.lang.Object. In this case, a java.lang.String instance is passed and used for displaying in the Progress Dialog. The schema used by any given application is arbitrary. This application uses the values in Table 3.

Build dynamic user interfaces with Android and XML

Page 35 of 42

developerWorks Table 3. The application values allowed for what


Value 0 1 2 Comment

ibm.com/developerWorks/

Obj contains a text string to display to the user. Successful completion of transmission, you're done! An error occurred. Tell the user that something is wrong and don't throw away the data!

Figure 15 shows the final message in the ProgressDialog upon a successful transmission of Form Data. Figure 15. Form submission

Once the form has been successfully submitted, the application returns to the main page. For a production-ready application, what takes place next is highly dependent on the motives of the data gathering organization. The screen can simply reset to take another entry, as in a physical inventory application. Or perhaps you can direct the user to some other screen. For the application to run properly, the AndroidManifest.xml file must contain references to all of the used Activity classes and must include the uses-permission for Internet access. Listing 16 shows the AndroidManifest.xml file for the tutorial's application.

Build dynamic user interfaces with Android and XML

Page 36 of 42

ibm.com/developerWorks/

developerWorks

Listing 16. The AndroidManifest.xml file


<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.msi.ibm" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".XmlGui" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".RunForm"> </activity> </application> <uses-permission android:name="android.permission.INTERNET"></uses-permission> </manifest>

Before wrapping up, take a brief look at the server side script.

Section 8. Provide a server side script


For the purposes of this tutorial, you will use a PHP script to gather the required data, and append it to a text file.

On the server
Exactly what transpires on the server is dependent on the needs of the organization collecting the data. A common approach for data collection is to store the form data in a relational database such as DB2, MySQL, SQL Server, Oracle, and so on. Once the data is in the database, it can be sliced, diced, and analyzed. For this tutorial, the data is gathered by a PHP script and appended to a text file. Listing 17 shows the PHP form associated with the Robotics registration form. Listing 17. The Robotic's PHP form
<?php // xmlgui form # 1 // this page is expecting // fname // lname // gender // age $filename = "/pathtowritablefile/datafile.txt";

Build dynamic user interfaces with Android and XML

Page 37 of 42

developerWorks
$f = fopen($filename,"a"); fprintf($f,"Data received @ ".date(DATE_RFC822)); fprintf($f,"\n"); fprintf($f,'First Name:['.$_POST['fname'].']'); fprintf($f,"\n"); fprintf($f,'Last Name:['.$_POST['lname'].']'); fprintf($f,"\n"); fprintf($f,'Gender:['.$_POST['gender'].']'); fprintf($f,"\n"); fprintf($f,'Age:['.$_POST['age'].']'); fprintf($f,"\n"); fclose($f); print "SUCCESS"; ?>

ibm.com/developerWorks/

If the script returns the string SUCCESS, the RunForm class will reset. Any other value will cause an error message to be displayed to the user and permit them to correct their entries or otherwise obtain help in submitting the form.

Section 9. Conclusion
This tutorial presented a framework for serving dynamic questions to an Android user based on a native application approach utilizing the Android SDK. You saw dynamic form presentation, validation and processing techniques, and application-to-web server communications.

Build dynamic user interfaces with Android and XML

Page 38 of 42

ibm.com/developerWorks/

developerWorks

Downloads
Description
Forms engine source code Information about download methods

Name
formsengine.zip

Size
78KB

Download method
HTTP

Build dynamic user interfaces with Android and XML

Page 39 of 42

developerWorks

ibm.com/developerWorks/

Resources
Learn Develop Android applications with Eclipse (Frank Ableson, developerWorks, February 2008): The easiest way to develop Android applications is to use Eclipse. Learn all about this in this developerWorks tutorial. Networking with Android (Frank Ableson, developerWorks, June 2009): Explore the networking capabilities of Android. Working with XML on Android (Michael Galpin, developerWorks, June 2009): Learn about the different options for working with XML on Android and how to use them to build your own Android applications. Unlocking Android, 2nd Edition (Frank Ableson, Robi Sen, and Chris King; Manning Publications; December 2010): Cover all aspects of Android development with concise, hands-on instruction for the Android operating system and development tools. Mobile Design and Development (Brian Fling, O'Reilly Media, 2009): Read about practical guidelines, standards, techniques, and best practices for building mobile products in this book. Android SDK documentation: Get the latest information in the Android API reference. The Open Handset Alliance: Visit Android's sponsor. Introduction to Android Development (Frank Ableson, developerWorks, May 2009): Get an introduction to the Android platform and learn how to code a basic Android application. Under the Hood of Native Web Apps for Android: Learn about hybrid applications in Android. More articles and tutorials by this author (Frank Ableson, developerWorks, April 2002-current): Read articles about Android, XML, Eclipse, GPS, BlackBerry applications, 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
Build dynamic user interfaces with Android and XML Page 40 of 42

ibm.com/developerWorks/

developerWorks

Android SDK: Download the Android SDK, access the API reference, and get the latest news on Android from the official Android developers' site. Version 1.5 and later will work for this article's exercise. Eclipse: Obtain the latest Eclipse IDE. Android Open Source Project: Android is open source, which means that you can get the source code here. 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.

Build dynamic user interfaces with Android and XML

Page 41 of 42

developerWorks

ibm.com/developerWorks/

About the author


Frank Ableson W. Frank Ableson is an entrepreneur living in northern New Jersey with his wife Nikki and their children. His professional interests include mobile software and embedded design. He is the author of Unlocking Android (Manning Publications, 2010), and he is the mobile editor for Linux Magazine. Copyright IBM Corporation 2010 (www.ibm.com/legal/copytrade.shtml) Trademarks (www.ibm.com/developerworks/ibm/trademarks/)

Build dynamic user interfaces with Android and XML

Page 42 of 42

Das könnte Ihnen auch gefallen