先决条件
在本文中,我们将创建一个在 Android 设备上运行的移动应用程序。您将需 要安装 Android SDK;本文使用 V1.5 SDK。应用程序代码将用Scala编程语言编写。如果您从来没用过 Scala,那么没有关系,因为本文将解释 Scala 代码 。但是,即使您不熟悉 Scala,建议您至少熟悉 Java 语言。本文使用 Scala V2.7.5 进行开发。对于 Android 和 Scala 都提供了很好的 Eclipse 插件。本 文使用 Eclipse V3.4.2 和 Android Development Tools(ADT) V0.9.1 以及 Scala IDE 插件 V2.7.5。
设置
编写 Android 应用程序听起来像是一个复杂的命题。Android 应用程序在它 们自己的虚拟机中运行:Dalvik 虚拟机。但是,Android 应用程序的构建路径 是开放的。下面表明了我们将使用的基本策略。
图 1. Android 上 Scala 的构建路径
其思想是,我们首先将所有 Scala 代码编译成 Java 类文件。这是 Scala 编译器的工作,所以这方面没什么太复杂的事情。接下来,获取 Java 类文件, 使用 Android dex 编译器将类文件编译成 Android 设备上的 Dalvik VM 使用 的格式。这就是所谓的 dexing,也是 Android 应用程序的常规编译路径。通常 ,要经历从 .java 文件到 .class 文件再到 .dex 文件的过程。在本文,惟一 不同的是我们从 .scala 文件开始。最后,.dex 文件和其他应用程序资源被压 缩成一个 APK 文件,该文件可安装到 Android 设备上。
那么,如何让这一切发生?我们将使用 Eclipse 做大部分工作。但是,此外 还有一个较复杂的步骤:要让代码运行,还需要来自标准 Scala 库中的代码。 在典型的 Scala 安装中,这是 /lib/scala-library.jar 中一个单独的 JAR。 但是,这个 JAR 包括一些不受 Android 支持的代码。有些代码需要稍作调整, 有些代码则必须移除。scala-library.jar 的定制构建是运行得最好的,至少目 前是这样。我们将把这个 JAR 称作 Android 库 JAR。
有了这个 JAR,剩下的事情就很容易了。只需使用 Eclipse 的 ADT 插件创 建一个 Android 项目。然后将一个 Scala 特性(nature)添加到项目中。用前 面谈到的 Android 库替代标准的 Scala 库。最后,将输出目录添加到类路径中 。现在,可以开始了。主 Scala 站点对此有更详细的描述。现在,我们有了基 本的设置,接下来看看我们将使用 Scala 创建的 Android 应用程序。
UnitsConverter
现在,我们知道如何利用 Scala 代码,将它转换成将在 Android 设备上运 行的二进制格式,接下来可以使用 Scala 创建一个移动应用程序。我们将创建 的应用程序是一个简单的单位转换应用程序。通过这个应用程序可以方便地在英 制单位与公制单位之间来回转换。这是一个非常简单的应用程序,但是我们将看 到,即使是最简单的应用程序也可以从使用 Scala 中获益。我们首先看看 UnitsConverter 的布局元素。
创建布局
您也许对编写手机上运行的 Scala 感到兴奋,但是并非所有的移动开发编程 都应该用 Scala 或 Java 语言完成。Android SDK 提供了一种很好的方式,使 用基于 XML 的布局系统将用户界面代码与应用程序逻辑分离。我们来看看本文 中的应用程序的主要布局文件,如清单 1 所示。
清单 1. Converter 应用程序的主要布局
<?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>