Scala+Eclipse+Android手機(jī)開發(fā)初探
眾所周知Android平臺(tái)上可以跑Java,因此運(yùn)行在JVM之上的Scala也可以跑。在本文中,我們將創(chuàng)建一個(gè)在 Android 設(shè)備上運(yùn)行的移動(dòng)應(yīng)用程序。您將需要安裝 Android SDK;本文使用 V1.5 SDK。應(yīng)用程序代碼將用 Scala 編程語(yǔ)言編寫。如果您從來沒用過 Scala,那么沒有關(guān)系,因?yàn)楸疚膶⒔忉?Scala 代碼。但是,即使您不熟悉 Scala,建議您至少熟悉 Java 語(yǔ)言。本文使用 Scala V2.7.5 進(jìn)行開發(fā)。對(duì)于 Android 和 Scala 都提供了很好的 Eclipse 插件。本文使用 Eclipse V3.4.2 和 Android Development Tools(ADT) V0.9.1 以及 Scala IDE 插件 V2.7.5。
51CTO編輯推薦:Scala編程語(yǔ)言專題
設(shè)置
編寫 Android 應(yīng)用程序聽起來像是一個(gè)復(fù)雜的命題。Android 應(yīng)用程序在它們自己的虛擬機(jī)中運(yùn)行:Dalvik 虛擬機(jī)。但是,Android 應(yīng)用程序的構(gòu)建路徑是開放的。下面表明了我們將使用的基本策略。
圖 1. Android 上 Scala 的構(gòu)建路徑
其思想是,我們首先將所有 Scala 代碼編譯成 Java 類文件。這是 Scala 編譯器的工作,所以這方面沒什么太復(fù)雜的事情。接下來,獲取 Java 類文件,使用 Android dex 編譯器將類文件編譯成 Android 設(shè)備上的 Dalvik VM 使用的格式。這就是所謂的 dexing,也是 Android 應(yīng)用程序的常規(guī)編譯路徑。通常,要經(jīng)歷從 .java 文件到 .class 文件再到 .dex 文件的過程。在本文,惟一不同的是我們從 .scala 文件開始。***,.dex 文件和其他應(yīng)用程序資源被壓縮成一個(gè) APK 文件,該文件可安裝到 Android 設(shè)備上。
那么,如何讓這一切發(fā)生?我們將使用 Eclipse 做大部分工作。但是,此外還有一個(gè)較復(fù)雜的步驟:要讓代碼運(yùn)行,還需要來自標(biāo)準(zhǔn) Scala 庫(kù)中的代碼。在典型的 Scala 安裝中,這是 /lib/scala-library.jar 中一個(gè)單獨(dú)的 JAR。但是,這個(gè) JAR 包括一些不受 Android 支持的代碼。有些代碼需要稍作調(diào)整,有些代碼則必須移除。scala-library.jar 的定制構(gòu)建是運(yùn)行得***的,至少目前是這樣。請(qǐng)參閱 參考資料,了解這里使用的定制構(gòu)建。我們將把這個(gè) JAR 稱作 Android 庫(kù) JAR。
有了這個(gè) JAR,剩下的事情就很容易了。只需使用 Eclipse 的 ADT 插件創(chuàng)建一個(gè) Android 項(xiàng)目。然后將一個(gè) Scala 特性(nature)添加到項(xiàng)目中。用前面談到的 Android 庫(kù)替代標(biāo)準(zhǔn)的 Scala 庫(kù)。***,將輸出目錄添加到類路徑中?,F(xiàn)在,可以開始了?,F(xiàn)在,我們有了基本的設(shè)置,接下來看看我們將使用 Scala 創(chuàng)建的 Android 應(yīng)用程序。
UnitsConverter
現(xiàn)在,我們知道如何利用 Scala 代碼,將它轉(zhuǎn)換成將在 Android 設(shè)備上運(yùn)行的二進(jìn)制格式,接下來可以使用 Scala 創(chuàng)建一個(gè)移動(dòng)應(yīng)用程序。我們將創(chuàng)建的應(yīng)用程序是一個(gè)簡(jiǎn)單的單位轉(zhuǎn)換應(yīng)用程序。通過這個(gè)應(yīng)用程序可以方便地在英制單位與公制單位之間來回轉(zhuǎn)換。這是一個(gè)非常簡(jiǎn)單的應(yīng)用程序,但是我們將看到,即使是最簡(jiǎn)單的應(yīng)用程序也可以從使用 Scala 中獲益。我們首先看看 UnitsConverter 的布局元素。
創(chuàng)建布局
您也許對(duì)編寫手機(jī)上運(yùn)行的 Scala 感到興奮,但是并非所有的移動(dòng)開發(fā)編程都應(yīng)該用 Scala 或 Java 語(yǔ)言完成。Android SDK 提供了一種很好的方式,使用基于 XML 的布局系統(tǒng)將用戶界面代碼與應(yīng)用程序邏輯分離。我們來看看本文中的應(yīng)用程序的主要布局文件,如清單 1 所示。
清單 1. Converter 應(yīng)用程序的主要布局
< ?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> |
以上代碼非常簡(jiǎn)潔地創(chuàng)建了該應(yīng)用程序的主 UI。它的根節(jié)點(diǎn)是一個(gè) RelativeLayout 容器元素。Android SDK 中有很多布局選項(xiàng)。RelativeLayout 指示運(yùn)行時(shí)使用相對(duì)定位對(duì)不同的 UI 小部件進(jìn)行布局。要使用相對(duì)定位,可添加可見元素 — 在這里是一個(gè) TextView 元素。這是用于顯示文本的一個(gè)簡(jiǎn)單的元素。它被賦予一個(gè) ID prompt_label。接下來的元素,即一個(gè) EditText 元素(一個(gè)文本輸入框)將用到它。這個(gè)元素有一個(gè) layout_below 屬性,它的值等于 prompt_label ID。換句話說,EditText 應(yīng)該放在名為 prompt_label 的元素的下方。
布局代碼剩下的部分非常簡(jiǎn)單。有一個(gè)帶標(biāo)簽的文本輸入框、一個(gè)帶標(biāo)簽的微調(diào)器(一個(gè)組合框或下拉框)、一個(gè)按鈕和一個(gè)用于輸出的文本框。圖 2 顯示正在運(yùn)行的應(yīng)用程序的一個(gè)截圖,其中標(biāo)出了不同的元素。
圖 2. Android lLayout — 分解圖
那么,以上視圖中看到的不同文本值來自哪里呢?注意,清單 1 中的一些元素有一個(gè) text 屬性。例如,prompt_label 元素有一個(gè)等于 @string/prompt_metric 的 text 屬性。這表明它將使用 Android 應(yīng)用程序中一個(gè)標(biāo)準(zhǔn)的資源文件:strings.xml 文件,如清單 2 所示。
清單 2. strings.xml 資源
< ?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> |
現(xiàn)在可以看到,圖 2 中所有的文本來自何處。微調(diào)器有一個(gè)下拉框,其中包含可用于度量的單位,那些單位在清單 2 中沒有列出。相反,它們來自另一個(gè)文件 arrays.xml,如清單 3 所示。
清單 3. arrays.xml 資源
< ?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> |
現(xiàn)在,我們可以看到將用于微調(diào)器的那些值。那么,這些值如何出現(xiàn)在微調(diào)器中,應(yīng)用程序如何在英制單位與公制單位之間切換?要回答這些問題,我們需要看看應(yīng)用程序代碼本身。
Scala 應(yīng)用程序代碼
Converter 應(yīng)用程序的代碼非常簡(jiǎn)單 — 不管用什么語(yǔ)言編寫。當(dāng)然,用 Java 編寫起來非常容易,但是用 Scala 編寫也同樣不復(fù)雜。首先我們看看前面見過的 UI 背后的代碼。
視圖背后的代碼
解釋創(chuàng)建 UI 的 Scala 代碼的最簡(jiǎn)單方式是先看看代碼,然后走查一遍。對(duì)于任何應(yīng)用程序,都是在應(yīng)用程序的 AndroidManifest.xml 文件中定義應(yīng)用程序的默認(rèn)活動(dòng)。任何 UI 背后都有一個(gè) Activity 類,默認(rèn)的 Activity 定義當(dāng)應(yīng)用程序初次裝載時(shí)執(zhí)行的 Activity 類。對(duì)于像本文這樣簡(jiǎn)單的應(yīng)用程序,有一個(gè) Converter 類,清單 4 中顯示了它的源代碼。
清單 4. Converter 活動(dòng)類
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) } } |
我們從這個(gè)類的頂部開始。它擴(kuò)展 android.app.Activity。這是一個(gè) Java 類,但是從 Scala 中可以對(duì) Java 類輕松地進(jìn)行細(xì)分。接下來,它有一些實(shí)例變量。每個(gè)實(shí)例變量對(duì)應(yīng)前面定義的一個(gè) UI 元素。注意,每個(gè)實(shí)例變量還被限定為 private[this]。這演示了 Scala 中特有的一種訪問控制級(jí)別,而 Java 語(yǔ)言中不存在這種訪問控制。這些變量不僅是私有的,而且只屬于 Converter 類的特定實(shí)例。這種級(jí)別的訪問控制對(duì)于移動(dòng)應(yīng)用程序來說有些大材小用,但是如果您是一名 Scala 開發(fā)人員,可以放心地在 Android 應(yīng)用程序上使用您熟悉的語(yǔ)法。
回到清單 4 中的代碼,注意,我們覆蓋了 onCreate 方法。這是 Activity 類中定義的方法,通常被定制的 Activity 覆蓋。如果用 Java 語(yǔ)言編寫該代碼,那么應(yīng)該添加一個(gè) @Override 標(biāo)注。在 Scala 中,override 是一個(gè)關(guān)鍵詞,用于確保正確性。這樣可以防止誤拼方法名之類的常見錯(cuò)誤。如果誤拼了方法名,Scala 編譯器將捕捉到方法名并返回一個(gè)錯(cuò)誤。注意,在這個(gè)方法上,以及任何其他方法上,不需要聲明返回類型。Scala 編譯器可以輕松推斷出該信息,所以不需要多此一舉。
onCreate 中的大部分代碼類似于 Java 語(yǔ)言編寫的代碼。但是有幾點(diǎn)比較有趣。注意,我們使用 findViewById 方法(在 Activity 子類中定義)獲得不同 UI 元素的句柄。這個(gè)方法不是類型安全的,需要進(jìn)行類型轉(zhuǎn)換(cast)。在 Scala 中,要進(jìn)行類型轉(zhuǎn)換,可使用參數(shù)化方法 asInstanceOf[T],其中 T 是要轉(zhuǎn)換的類型。這種轉(zhuǎn)換在功能上與 Java 語(yǔ)言中的轉(zhuǎn)換一樣。不過 Scala 有更好的語(yǔ)法。接下來,注意對(duì) setUomChoice 的調(diào)用(稍后我們將詳細(xì)談到這個(gè)方法)。***,注意上述代碼獲得一個(gè)在布局 XML 中創(chuàng)建的按鈕的句柄,并添加一個(gè)單擊事件處理程序。
如果用 Java 語(yǔ)言編寫,那么必須傳入 Android 接口 OnClickListener 的一個(gè)實(shí)現(xiàn)。這個(gè)接口只定義一個(gè)方法:onClick。實(shí)際上,您關(guān)心的只是那個(gè)方法,但是在 Java 語(yǔ)言中無法直接傳入方法。而在 Scala 中則不同,在 Scala 中可以傳入方法字面量(literal)或閉包。在這里,我們用語(yǔ)法 () => { ... } 表示閉包,其中方法的主體就是花括號(hào)中的內(nèi)容。開始/結(jié)束括號(hào)表示一個(gè)不帶參數(shù)的函數(shù)。但是,我將這個(gè)閉包傳遞到 Button 的一個(gè)實(shí)例上的 setOnClickListener 方法,Button 是 Android SDK 中定義的一個(gè) Java 類。如何將 Scala 閉包傳遞到 Java API?我們來看看。
Android 上的函數(shù)式編程
為了理解如何讓 Android API 使用函數(shù)字面量,看看 Converter 類定義的***行。這是一條重要的語(yǔ)句。這是 Scala 的另一個(gè)很好的特性。您可以在代碼的任何地方導(dǎo)入包、類等,它們的作用域限于導(dǎo)入它們的文件。在這里,我們導(dǎo)入 ConverterHelper 中的所有東西。清單 5 顯示 ConverterHelper 代碼。
清單 5. 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} } |
這是一個(gè) Scala 單例(singleton),因?yàn)樗褂脤?duì)象聲明,而不是類聲明。單例模式被直接內(nèi)置在 Scala 中,可以替代 Java 語(yǔ)言中的靜態(tài)方法或變量。在這里,這個(gè)單例存放一對(duì)函數(shù):funcToClicker 和 funcToClicker0。這兩個(gè)函數(shù)以一個(gè)函數(shù)作為輸入?yún)?shù),并返回 OnClickListener 的一個(gè)實(shí)例,OnClickListener 是 Android SDK 中定義的一個(gè)接口。例如,funcToClicker 被定義為以一個(gè)函數(shù) f 為參數(shù)。這個(gè)函數(shù) f 的類型為帶一個(gè) View 類型(Android 中的另一個(gè)類)的輸入?yún)?shù)的函數(shù),并返回 Unit,它是 void 在 Scala 中的對(duì)等物。然后,它返回 OnClickListener 的一個(gè)實(shí)現(xiàn),在這個(gè)實(shí)現(xiàn)中,該接口的 onClick 方法被實(shí)現(xiàn)為將輸入函數(shù) f 應(yīng)用到 View 參數(shù)。另一個(gè)函數(shù) funcToClick0 也做同樣的事情,只是以一個(gè)不帶輸入?yún)?shù)的函數(shù)為參數(shù)。
這兩個(gè)函數(shù)(funcToClicker 和 funcToClicker0)都被定義為隱式函數(shù)(implicit)。這是 Scala 的一個(gè)方便的特性。它可以讓編譯器隱式地將一種類型轉(zhuǎn)換成另一種類型。在這里,當(dāng)編譯器解析 Converter 類的 onCreate 方法時(shí),它遇到一個(gè) setOnClickListener 調(diào)用。這個(gè)方法需要一個(gè) OnClickListener 實(shí)例。但是,編譯器卻發(fā)現(xiàn)一個(gè)函數(shù)。在報(bào)錯(cuò)并出現(xiàn)編譯失敗之前,編譯器將檢查是否存在隱式函數(shù),允許將函數(shù)轉(zhuǎn)換為 OnClickListener。由于確實(shí)還有這樣的函數(shù),所以它執(zhí)行轉(zhuǎn)換,編譯成功?,F(xiàn)在,我們理解了如何使用 Android 中的閉包,接下來更仔細(xì)地看看應(yīng)用程序邏輯 — 特別是,如何執(zhí)行單位轉(zhuǎn)換計(jì)算。
單位轉(zhuǎn)換和計(jì)算
我們回到清單 4。傳入 onClickListener 的函數(shù)收到用戶輸入的度量單位和值。然后,它創(chuàng)建一個(gè) Measurement 實(shí)例,并將該實(shí)例傳遞到一個(gè) UnitsConverter 對(duì)象。清單 6 顯示相應(yīng)的代碼。
清單 6. Measurement 和 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 是一個(gè) case 類。這是 Scala 中的一個(gè)方便的特性。用 “case” 修飾一個(gè)類會(huì)導(dǎo)致這個(gè)類生成這樣一個(gè)構(gòu)造函數(shù):這個(gè)構(gòu)造函數(shù)需要類的屬性,以及 equals、 hashCode 和 toString 的實(shí)現(xiàn)。它對(duì)于像 Measurement 這樣的數(shù)據(jù)結(jié)構(gòu)類非常適合。它還為定義的屬性(在這里就是 uom 和 amount)生成 getter 方法。也可以將那些屬性定義為 vars(可變變量),然后也會(huì)生成 setter 方法。僅僅一行 Scala 代碼可以做這么多事情!
接下來,UnitsConverter 也是一個(gè)單例模式,因?yàn)樗鞘褂?object 關(guān)鍵詞定義的。它只有一個(gè) convert 方法。注意,convert 被定義為相當(dāng)于一條單一語(yǔ)句 — 一條 match 語(yǔ)句。它是一個(gè)單一表達(dá)式,所以不需要額外的花括號(hào)。它使用 Scala 的模式匹配。這是函數(shù)式編程語(yǔ)言中常見的一個(gè)強(qiáng)大特性。它類似于 Java 語(yǔ)言和很多其他語(yǔ)言中的 switch 語(yǔ)句。但是,我們可以匹配字符串(實(shí)際上,還可以有比這高級(jí)得多的匹配)。如果字符串匹配,則執(zhí)行適當(dāng)?shù)挠?jì)算,并返回格式化的字符串,以供顯示。***,注意與 _ 匹配的***一個(gè) case。Scala 中的很多地方使用下劃線作為通配符。在這里,它表示匹配任何東西,這類似于 Java 語(yǔ)言中的 default 語(yǔ)句。
現(xiàn)在,我們理解了應(yīng)用程序中的計(jì)算,***來看看剩下的 UI 設(shè)置和菜單。
UI 初始化和菜單
回到清單 4。我們說過要看看 setUomChoice。這個(gè)方法被定義為帶有一個(gè) UnitsSystem 類型的參數(shù)。我們來看看如何定義這個(gè)類型。
清單 7. UnitsSystem
sealed case class UnitsSystem() case object ENGLISH extends UnitsSystem case object METRIC extends UnitsSystem |
我們看到,UnitsSystem 是一個(gè)密封的 case 類,沒有屬性??瓷先ニ皇呛苡杏谩=酉聛?,我們看看兩個(gè) case 對(duì)象。還記得嗎,object 表示 Scala 中的一個(gè)單例。在這里,有兩個(gè) case 對(duì)象,每個(gè) case 對(duì)象都擴(kuò)展 UnitsSystem。這是 Scala 中的一個(gè)常見的特色,它可以提供更簡(jiǎn)單、更類型安全的枚舉方式。
現(xiàn)在 setUomChoice 的實(shí)現(xiàn)更加合理。在獲得微調(diào)器的一個(gè)句柄后,我們匹配傳入的 UnitsSystem 的類型。這標(biāo)識(shí)了我們?cè)谇懊嬉姷降?arrays.xml 中的一個(gè)數(shù)組。這是使用 Android SDK 生成的 R 類表示資源,例如 arrays.xml 文件。一旦知道使用哪個(gè)數(shù)組,我們就通過創(chuàng)建一個(gè)傳入微調(diào)器的適配器(在這里是一個(gè) ArrayAdapter),使用那個(gè)數(shù)組作為微調(diào)器的數(shù)據(jù)源。
***,看看清單 4 中的 onCreateOptionsMenu 和 onMenuItemSelected 方法。這些方法是在 Activity 中定義的,我們將在 Converter 活動(dòng)中覆蓋這些方法。***個(gè)方法創(chuàng)建一個(gè)菜單。第二個(gè)方法處理用戶從菜單中選擇 English 或 metric 的事件。它再次調(diào)用 setUomChoice。這使用戶可以在從英制單位轉(zhuǎn)換為公制單位與從公制單位轉(zhuǎn)換為英制單位之間進(jìn)行切換。
結(jié)束語(yǔ)
Android 平臺(tái)的架構(gòu)使它可以用于在 Java 虛擬機(jī)上運(yùn)行的任何編程語(yǔ)言。我們看到了如何設(shè)置 Android 項(xiàng)目,使它使用 Scala 代碼。這個(gè)過程也可以延伸到其他 JVM 編程語(yǔ)言,例如 Groovy、JRuby 或 Fan。當(dāng)可以任意使用 Scala 編程語(yǔ)言時(shí),編寫 Android 應(yīng)用程序?qū)⒆兊酶p松。您仍可以使用 Eclipse 進(jìn)行開發(fā)。仍然可以在 Eclipse 中用模擬器和設(shè)備進(jìn)行調(diào)試。您可以繼續(xù)使用所有的工具,同時(shí)又得到一種生產(chǎn)率更高的編程語(yǔ)言。
【相關(guān)閱讀】