In this article, we will create a mobile application that will run on any Android device. You will need to install the Android SDK; Android V1.5 SDK was used here. The application code will be written in the Scala programming language. If you have never seen Scala before, that is OK because the Scala code will be explained. However, it is recommended that you are at least familiar with the Java language if you are not familiar with Scala. Scala V2.7.5 was used to develop the code in this article. For Android and Scala, there are excellent Eclipse plug-ins available. Eclipse V3.4.2 was used, along with Android Development Tools (ADT) V0.9.1 and V2.7.5 of the Scala IDE plug-in. See Resources for all of these tools.
Writing an Android application may sound like a tricky proposition. Android applications run inside their own virtual machine: the Dalvik virtual machine. However, the build path for an Android application opens things up for us. The basic strategy we will use is illustrated below.
Figure 1. Build path for Scala on Android
The idea is that we will first compile all of the Scala code to Java class files. This is what the Scala compiler does, so there is nothing too tricky about this. Next, we take the Java class files and use the Android dex compiler to compile the class files to the format used by the Dalvik VM on an Android device. This is known as dexing and is the normal compile path for an Android application. Usually, you go from .java files to .class files to a single .dex file. The only thing different in our case is that we start with .scala files. Finally, the .dex file and other application resources are zipped up as an APK file that can be installed on an Android device.
So how do we make all of this happen? We will use Eclipse to do most of the heavy lifting for us. However, there is one tricky step: For our code to run, it also needs code from the standard Scala library. In a typical Scala installation, this is a single JAR found in /lib/scala-library.jar. This JAR, however, includes certain code not supported on Android. Some code needs to be tweaked slightly, and some code must be removed. A custom build of scala-library.jar works best, at least for now. See Resources for the custom build used here. We will refer to this JAR as the Android library JAR.
Once we have that JAR, the rest is pretty easy. Just create an Android project using the ADT plug-in for Eclipse. Then add a Scala nature to the project. Replace the standard Scala library with the Android library talked about above. Finally, add the output directory to your classpath. Now you are ready to go. This is described in more detail in a note from the main Scala site (see Resources). Now that we have the basic setup, let's take a look at the Android application we will create using Scala.
Now that we know how to take Scala code and turn it into the binary format that
will run on an Android device, it's time to create a mobile
application using Scala. The application we will create will be a
simple unit-converter application. This will let users easily convert
from English to metric units and vice-versa. This is a pretty simple
application, but we will see how even the simplest applications can
benefit from using Scala. Let's start out by looking at the layout
elements of UnitsConverter.
You might be excited to write Scala that runs on your phone, but not all mobile development coding should be done in Scala, or the Java language, for that matter. The Android SDK provides a nice way to separate the user-interface code from application logic using an XML-based layout system. Let's look at the main layout file for our application, shown in Listing 1.
Listing 1. Main layout for the Converter application
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:gravity="center_horizontal" android:padding="10px"
>
<TextView android:id="@+id/prompt_label" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/prompt_metric"/>
<EditText android:id="@+id/amount" android:layout_below="@id/prompt_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/uom_label"
android:layout_below="@id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/uom"/>
<Spinner android:id="@+id/uom_value"
android:layout_below="@id/uom_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:id="@+id/convert_button"
android:layout_below="@id/uom_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/convert_button_label"/>
<TextView android:id="@+id/result_value"
android:layout_below="@id/convert_button"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</RelativeLayout>
|
The above code very succinctly creates the main UI for
the application. Its root node is a
RelativeLayout container element. There are
many layout options available in the Android SDK. A
RelativeLayout simply instructs the runtime to
lay out various UI widgets using relative positioning. To use relative
positioning, we add a visible element — in this case, a
TextView element. This is a simple element for
displaying text. It is assigned an ID of
prompt_label. This is used by the next element,
an EditText element (a text input box). This
element has a layout_below attribute for which
the value is equal to the prompt_label ID. In other
words, EditText should be placed below the
element called prompt_label.
The rest of the layout code is very straightforward. All together, there is a text input box with a label, a spinner (a combo box or a drop-down) with a label, a button, and a another text area for output. Figure 2 shows a picture of the running application, with elements identified.
Figure 2. An Android lLayout — dissected
So where do the various text values seen in the above view come from?
Notice that several of the elements in Listing 1 have a text attribute.
For example, the prompt_label element has a
text attribute equal to @string/prompt_metric.
That indicates it is using one of the standard resource files in an
Android application: the strings.xml file, shown in Listing 2.
Listing 2. The strings.xml resource
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="prompt_metric">Enter amount (KM, g, L, C)</string>
<string name="prompt_english">Enter amount (miles, lbs, gallons,
F)</string>
<string name="uom">Units of Measure</string>
<string name="convert_button_label">Convert</string>
<string name="app_name">Converter</string>
<string name="english_units">English</string>
<string name="metric_units">Metric</string>
</resources>
|
Now you can see where all of the text in Figure 2 is coming from. The spinner has a drop-down of possible units of measure to use, and those units are not listed in Listing 2. Instead, they come from another file, arrays.xml, shown in Listing 3.
Listing 3. The arrays.xml resource
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="english_units">
<item>Fahrenheit</item>
<item>Pounds</item>
<item>Ounces</item>
<item>Fluid Ounces</item>
<item>Gallons</item>
<item>Miles</item>
<item>Inches</item>
</array>
<array name="metric_units">
<item>Celsius</item>
<item>Kilograms</item>
<item>Grams</item>
<item>Millileters</item>
<item>Liters</item>
<item>Kilometers</item>
<item>Centimeters</item>
</array>
</resources>
|
Now we can see the values that will be used for the spinner. How do these actually wind up in the spinner, and how can the application toggle between English and metric units? To answer those questions, we have to take a look at the application code itself.
The application code for the Converter application is pretty simple — in any language. It could, of course, be done relatively easily in the Java language, but it is certainly no more complex to do it in Scala. In fact, as we will see, many things are made much simpler by using Scala. Let's start by looking at the code behind the UI we have been examining.
The easiest way to explain the Scala code that helps create the UI is to
take a look at it and go through it. For any application,
you define the default activity of your application in the application's
AndroidManifest.xml file. Any UI is backed up by an
Activity class, and the default
Activity defines the
Activity class executed when the
application is initially loaded. For an application as simple as this one,
this is the only activity needed. For this
application, a class called Converter is
listed, and its source code is shown in Listing 4.
Listing 4. The
Converter activity class
class Converter extends Activity{
import ConverterHelper._
private[this] var amountValue:EditText = null
private[this] var uom:Spinner= null
private[this] var convertButton:Button = null
private[this] var resultValue:TextView = null
override def onCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
uom = findViewById(R.id.uom_value).asInstanceOf[Spinner]
this.setUomChoice(ENGLISH)
amountValue = findViewById(R.id.amount).asInstanceOf[EditText]
convertButton = findViewById(R.id.convert_button).asInstanceOf[Button]
resultValue = findViewById(R.id.result_value).asInstanceOf[TextView]
convertButton.setOnClickListener( () => {
val unit = uom.getSelectedItem.asInstanceOf[String]
val amount = parseDouble(amountValue.getText.toString)
val result = UnitsConverter.convert(Measurement(unit,amount))
resultValue.setText(result)
})
}
override def onCreateOptionsMenu(menu:Menu) = {
super.onCreateOptionsMenu(menu)
menu.add(NONE, 0, 0, R.string.english_units)
menu.add(NONE, 1, 1, R.string.metric_units)
true
}
override def onMenuItemSelected(featureId:Int, item:MenuItem) = {
super.onMenuItemSelected(featureId, item)
setUomChoice(if (item.getItemId == 1) METRIC else ENGLISH)
true
}
private
def setUomChoice(unitOfMeasure:UnitsSystem){
if (uom == null){
uom = findViewById(R.id.uom_value).asInstanceOf[Spinner]
}
val arrayId = unitOfMeasure match {
case METRIC => R.array.metric_units
case _ => R.array.english_units
}
val units = new ArrayAdapter[String](this, R.layout.spinner_view,
getResources.getStringArray(arrayId))
uom.setAdapter(units)
}
}
|
Let's start at the top of this class. It extends
android.app.Activity. This is a Java class, but
you can easily subclass Java classes from Scala. Next, it has
several instance variables. Each of these corresponds to a UI element
defined earlier. Notice that each is also scoped as
private[this]. This demonstrates a level of
access control available in Scala that does not exist in the Java language. Not only
are the variables private but they are private to the particular instance
of the Converter class. This level of access
control might be overkill for a mobile application, but if you happen to
be a Scala developer, it is reassuring that all of the syntax
you are accustomed to is still available on an Android application.
Getting back to the code in Listing 4, notice that we override the
onCreate method. This is a method defined in
the Activity class and is typically overridden
by any custom Activity. If you were writing
this code in the Java language, you should add an @Override
annotation. In Scala, override is a keyword, required to help
ensure correctness. This would prevent a common mistake like misspelling
the method name. If you misspelled it, the Scala compiler would catch
this and give you an error. Notice that on this method, as well as all of
the others, you do not need to declare a return type. The Scala compiler
is easily able to infer this information, so there's no need to be
redundant.
Most of the code in onCreate is similar to
what you would do in the Java language. There are a couple of things of interest.
Notice that we use the method findViewById
(defined in the superclass Activity) to get a
handle on various UI elements. This method is not type-safe and requires
a cast. To typecast in Scala, use the parameterized method
asInstanceOf[T], where
T is the type you are casting to. The cast
is functionally just like it would be in the Java language; Scala just has nicer syntax
for it. Next, notice the call to setUomChoice
(we will go into detail on this method shortly). Finally, notice that we get
a handle on the button we created in the layout XML and add a click event
handler.
If this was written in the Java language, we would have to pass in an
implementation of the Android interface
OnClickListener. This interface defines a
single method: onClick. Really, all you care
about is that method, but there is no way to pass in a method directly in
the Java language. This is not the case in Scala, where we are able to pass in a method
literal, or closure. Here, we are denoting a closure by using the syntax
() => { ... }, where the method body is
the contents of the curly braces. The open/close parentheses denote a
function that takes no parameters. However, we are passing this closure to
the setOnClickListener method on an instance of
Button, a Java class defined in the Android SDK. How can we pass a Scala
closure to a Java API? Let's take a look.
Functional programming on Android
To understand how we get Android APIs to work with function literals, look
at the first line of the Converter class
definition. It is an import statement. This is another nice feature of
Scala. You can import packages, classes, etc. anywhere in the code, and
they are scoped to where you import them. In this case, we are importing
everything from something called
ConverterHelper. The code for
ConverterHelper is shown in Listing 5.
Listing 5. The
ConverterHelper
object ConverterHelper{
import android.view.View.OnClickListener
implicit def funcToClicker(f:View => Unit):OnClickListener =
new OnClickListener(){ def onClick(v:View)=f.apply(v)}
implicit def funcToClicker0(f:() => Unit):OnClickListener =
new OnClickListener() { def onClick(v:View)=f.apply}
}
|
This is a Scala singleton because it uses the object declaration instead
of a class declaration. The singleton pattern is baked directly into
Scala and is used anywhere you would use static methods or variables
in the Java language. In this case, the singleton simply holds a pair of functions:
funcToClicker and
funcToClicker0. These take a function
as an input parameter and return an instance of
OnClickListener, the interface defined in the
Android SDK. For example, funcToClicker is
defined as taking a function f. The function
f is type as a function that takes a single
input parameter of type View (another class
from Android) and returns Unit, which is the
Scala equivalent of void. It then returns an implementation of
OnClickListener, where that interface's
onClick method is implemented by simply
applying the input function f to the
View parameter. The other function,
funcToClick0, does the same thing, but takes
a function that has no input parameter.
Both of these functions (funcToClicker and
funcToClicker0) are defined as implicit. This a
convenient feature of Scala. It allows types to be
implicitly converted to another type by the compiler. In this case, when
the compiler parses the Converter class's
onCreate method, it encounters a call to
setOnClickListener. This is a method that
requires an instance of OnClickListener.
However, the compiler finds a function, instead. Before it complains
and compilation fails, the compiler checks to see if there are any
implicit functions in scope that would allow it to convert the function to
an OnClickListener. Indeed, there is, so it
performs this conversion, and all is well. Now that we understand how to
use closures within Android, let's take a look at more of the application
logic — in particular, how the unit-conversion calculations are
performed.
Unit conversions and calculations
Let's go back to Listing 4. The function passed in to
onClickListener retrieves the units of
measurement and the value entered by the user. It then creates a
Measurement instance and passes this to an
object called UnitsConverter. The code for
these entities is shown in Listing 6.
Listing 6.
Measurement and
UnitsConverter
case class Measurement(uom:String, amount:Double)
object UnitsConverter{
// constants
val lbToKg = 0.45359237D
val ozToG = 28.3495231
val fOzToMl = 29.5735296
val galToL = 3.78541178
val milesToKm = 1.609344
val inchToCm = 2.54
def convert (measure:Measurement)= measure.uom match {
case "Fahrenheit" => (5.0/9.0)*(measure.amount - 32.0) + " C"
case "Pounds" => lbToKg*measure.amount + " kg"
case "Ounces" => ozToG*measure.amount + " g"
case "Fluid Ounces" => fOzToMl*measure.amount + " mL"
case "Gallons" => galToL*measure.amount + " L"
case "Miles" => milesToKm*measure.amount + " km"
case "Inches" => inchToCm*measure.amount + " cm"
case "Celsius" => (9.0/5.0*measure.amount + 32.0) + " F"
case "Kilograms" => measure.amount/lbToKg + " lbs"
case "Grams" => measure.amount/ozToG + " oz"
case "Millileters" => measure.amount/fOzToMl + " fl. oz."
case "Liters" => measure.amount/galToL + " gallons"
case "Kilometers" => measure.amount/milesToKm + " miles"
case "Centimeters" => measure.amount/inchToCm + " inches"
case _ => ""
}
}
|
Measurement is a case class. This is a
convenience feature of Scala. Decorating a class with "case" causes it to
have a constructor generated that requires the attributes of the class, as
well as implementations of equals,
hashCode, and
toString. It is perfect for data structure
classes, like Measurement. It also generates
getters for the attributes defined — in this case, uom and amount. We could
have defined those attributes as vars (mutable variables), then
setters would have also been generated for us. That single line of Scala
code does a lot!
Next, UnitsConverter is also a singleton as it
is defined using the object keyword. Its single method is convert. Notice
how convert is defined as being equal to a single statement — a match
statement. It is a single expression, so no extra curly braces are needed.
It uses Scala's pattern matching. This is a powerful feature common in
functional programming languages. It is similar to a switch statement in
the Java language and many other languages. However, we are able to match against
strings (actually, the matching can be much more sophisticated than this.)
The string is matched, the
appropriate calculation is performed, and a formatted string is returned
to be displayed. Finally, notice the last case that matches
_. The underscore is used as a wildcard in many
places in Scala. In this case, it says match anything, kind of like a
default statement in the Java language.
Now that we understand the calculations in the application, let's finish off the application by looking at the rest of the UI setup and menus.
Let's go back to Listing 4. We promised to look at the
setUomChoice. This method is defined as taking
a parameter of type UnitsSystem. Let's take a
look at how this type is defined.
Listing 7. The
UnitsSystemsealed case class UnitsSystem() case object ENGLISH extends UnitsSystem case object METRIC extends UnitsSystem |
We see that UnitsSystem is a sealed case class
with no attributes. That doesn't seem very useful. Next, we see two case
objects. Remember that object denotes a
singleton in Scala. In this case, there are two case
objects and each extend UnitsSystem. This is a common idiom in Scala to
provide a simpler, more type-safe way of doing enumerations.
Now the implementation of setUomChoice makes
more sense. After we get a handle on the spinner, we match against what
type of UnitsSystem was passed in. This
identifies an array to use from the arrays.xml we saw earlier. This
is using the R class that the Android SDK
generates for us to represent resources, such as the arrays.xml file. Once
we know which array to use, we use that array as the data source of the
spinner by creating an adapter (in this case, an
ArrayAdapter) that we pass in to the
spinner.
Finally, look at the onCreateOptionsMenu and
onMenuItemSelected methods from Listing 4.
These are methods defined in Activity we are overriding in our
Converter activity. The first method creates a menu. The second handles
the event of a user selecting either English or metric from the menu. It
simply calls the setUomChoice again. This allows the user to toggle
between converting from English to metric units, or from metric to English
units.
The architecture of the Android platform opens it up to any programming language that runs on the Java Virtual Machine. We have seen how to set up an Android project to work with Scala code. This type of procedure can be extended to other JVM programming languages, as well, like Groovy, JRuby, or Fan. With the Scala programming language at our disposal, it becomes even easier to write Android applications. You are still able to develop using Eclipse. Debugging both with the emulator and a device work straight from Eclipse, as well. You get all of the tools and a more productive programming language.
| Description | Name | Size | Download method |
|---|---|---|---|
| Converter sample | os-eclipse-scala-Converter.zip | 2KB | HTTP |
Information about download methods
Learn
-
Read the "Develop Android
applications with Eclipse" tutorial.
-
Read Scala and Android in an Eclipse project
for an introduction on how to build Scala Eclipse projects for Android.
-
Check out "The busy Java
developer's guide to Scala" for a comprehensive tour of
Scala.
-
Scala can make many common
programming tasks easier, including working with XML. See how in "Scala and XML."
-
Scala powers Lift, an
innovative Web application framework. Get an introduction to Lift in "Give Apache
Geronimo a Lift."
-
Read "Build Comet
applications using Scala, Lift, jQuery" to see how Lift can enable
advanced Ajax and Comet development.
-
For the latest information about Scala,
check out the Scala Web site.
-
Get the Android SDK documentation.
-
Check out The Open Handset
Alliance, Android's sponsor.
-
Read Unlocking
Android, a great resource for learning Android.
-
Check out the "Recommended Eclipse reading list."
-
Browse all the Eclipse content on developerWorks.
-
Follow developerWorks on Twitter.
-
New to Eclipse? Read the developerWorks article "Get started with the Eclipse Platform" to learn its origin and architecture, and how to extend Eclipse with plug-ins.
-
Expand your Eclipse skills by checking out IBM developerWorks' Eclipse project resources.
-
To listen to interesting interviews and discussions for software developers, check out check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
Get products and technologies
-
Download the Android SDK,
access the API reference, and get the latest news on Android from the
official Android developers' site.
-
Android is open source, which means that you can get the source code for it from the
Android Open Source Project.
-
Check out the latest Eclipse technology downloads at IBM alphaWorks.
-
Download Eclipse Platform and other projects from the Eclipse Foundation.
- Download
IBM product evaluation versions
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®.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
-
The Eclipse Platform newsgroups should be your first stop to discuss questions regarding Eclipse. (Selecting this will launch your default Usenet news reader application and open eclipse.platform.)
-
The Eclipse newsgroups has many resources for people interested in using and extending Eclipse.
-
Participate in developerWorks blogs and get involved in the developerWorks community.
Comments (Undergoing maintenance)






