Thursday, January 29, 2009

Android View XML

I am thoroughly enjoying using XML to define the view characteristics of my Android application. I've written GUI code in Visual Basic, Swing, RCP, and a dab of GTK+. None of them are as easy and elegant as using XML. I applaud the Android team in using this approach.

Don't forget to apply some style to your view. Who would want to look at some boring, white standard font. Checkout the Android documentation on styles and themes.

But don't stop at using only the view components that Android supplies. Good object oriented design encompasses creating custom view components for your custom data objects. If you have a domain object called Person that needs to be displayed then you should have a custom composite view that knows exactly how a Person is displayed -- err, the attributes of the person are displayed. I learned over here that using custom view controls in the XML is as easy as defining an xml element with the name of your custom view.

I put together the below example as a guide. It is not meant to be an exemplar. Note that i have a LinearLayout that defines padding. That likely belongs in a style instead of being defined solely for THAT LinearLayout. With that warning in place, here's an exmple of a my.app.PersonComposite which is a custom class that extends LinearLayout. To use this custom view component in your XML then you would include something like the following:
<my.app.PersonComposite
android:id="@+id/person"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
So, that element will put a PersonComposite in your activity. But what does the PersonComposite look like? Well, that should be defined in xml as well. In the constructors of PersonComposite, include the following:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.person_composite, this);

In order for this to work, you'll need to have a ./res/layout/person_composite.xml. Perhaps something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:padding="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
style="@style/BigAndBlue"
android:id="@+id/personLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>

<TextView
android:id="@+id/personFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>
</LinearLayout>
Note that the style attribute conspicuously lacks the android namespace. Hmm? Oh well, just watch out for that. We have to define that Style over in ./res/values/styles.xml:
<resources>
<style name="BigAndBlue">
<item name="android:textSize">12pt</item>
<item name="android:textColor">#008</item>
</style>
</resources>

Tuesday, January 13, 2009

Unit Testing Android Applications

Unit testing my Android application has put strain on my patience. All of my unit tests are not just one quick key stroke. I already posted regarding mock testing an Android project. Integration tests are another issue. These tests have to run inside the container -- the emulator or phone. I got started writing integration tests by reading this document. You'll find more Android topics discussed at his blog.

I followed Diego's steps to setup the test-specific eclipse project. Then I created an external tool configuration to launch the tests:
The "Functional Tests" run configuration changes the arguments to:
shell am instrument -w -e func true com.wilson.android.libary.test/android.test.InstrumentationTestRunner
Now each time I'm ready to run the tests I need to deploy the main project, the test project -- if they both changed. Now I can use one of the run configurations above to use "adb" to launch the tests.

Be sure to read the official documentation on running instrumentation tests, starting here.