轉自 :http://www.madeye.me/2013/05/09/scala-in-android/
Why?
Android 開發一直有兩個無法迴避的問題:基於 JVM 的設計使得系統的性能受到拖累;Java 冗繁的語法令人絕望。
手機性能的大幅提升、Android 系統的持續改進,以及應用中 NDK 的廣泛使用使得 JVM 帶來的額外開銷變得微不足道。但 Java 作爲一門民工語言已經遠遠落後於時代潮流則是無法改變的事實。更令人揪心的是,落在 Oracle 手上的 Java 對於整個開源社區來說都是潛在的威脅,這一點從 Oracle 針對 Google 的一系列 Android 相關的訴訟就可以大概明瞭。
Scala 作爲一門 state-of-the-art 的編程語言,兼具面向對象以及函數式語言的特點。其設計在 JVM 之上,與 Java 類庫完全兼容,甚至可以與 Java 代碼相互轉換。另外 Scala 以類似 BSD 的協議發佈,對於開源社區也更爲友好。總的來看,Scala 是當前替代 Java 的最好選擇,在不需要放棄已經無比先進的 JVM 和足夠完備的 Java 生態的前提下,開發者們可以獲得更先進的語言特性和更高的開發效率。實際上類似的目標在 Groovy 和 JRuby 中都有所體現,但都做得不好。
至於 Android 開發,Scala 則提供了全新的體驗。以一段常見的 Android 代碼爲例,在配合 Scaloid 的情況下代碼量可以大大減少。
Register BroadcastReceiver in Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
上面是 Java 的實現,可以看出兩個問題:Java 的回調用的是匿名類,顯得頗爲繁瑣;註冊與反註冊這樣一對調用需要成對出現,當代碼量變大時,一不小心就會漏掉。
Register BroadcastReceiver in Scala
1 2 3 |
|
同樣的功能,用 Scala 實現的代碼可以非常簡潔:函數式的寫法替代了匿名類;隱式的方法被用來統一管理生命週期。
類似的例子還有很多,在這裏就不逐一列出了,有興趣的可以關注 Scala Android Blog。
How?
現階段使用 Scala 開發的 Android 應用還不多,技術上也不夠統一。在被坑了幾次後,總算有了一套靠譜的方案。
若是想要在現有的 Android 項目的基礎上進行重構,建議先將項目 Maven 化,具體方法可以見本博客的上一篇文章。在此基礎上通過將 Maven 替換爲 SBT,並引入 sbt-android-plugin 這個插件,可以快速重構爲標準的 Scala 項目結構。一個典型的 Scala Android 項目如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
需要注意的是項目中的 AndroidManifest.xml
是不含 android:version
和 android:versionCode
這兩個屬性的。這兩個屬性會根據 Build.scala
中的設定自動生成。
在重構代碼之前,我們可以把已有的 Java 和 JNI 代碼放置到相應目錄中,將所有的依賴加入 Build.scala
文件或放在 libs
文件夾下。之後則可以挨個的將原來的
Java 代碼重構爲 Scala。
Scala 是支持和 Java 混合編譯的,因此你可以隨時執行以下命令編譯並測試:
1 2 3 4 5 |
|
Android 的接口是專爲 Java 設計的,而爲了寫出更加地道的 Scala 代碼,建議再引入 Scaloid 來簡化 API 的調用。當熟練使用 Scala 編寫代碼後,代碼量可以減少至少一半。
一個完整的例子可以見我的 shadowsocks-android 項目。而更多的細節請參考 sbt-android-plugin 的 Wiki 頁面。
Tips
學習 Scala
Scala 雖然許多地方長的和 Java 很像,但是想要寫出「函數式」的風格需要重新學習很多內容。對於比較資深的 Java 程序員,建議直接去看《Programming in Scala》這本書,和《Scala API Doc》。之前還翻過一本《Scala for the Impatient》,標題很誘人但內容太淺顯,這裏不做推薦。
sbt-android-plugin
由於缺乏文檔,sbt-android-plugin 裏有不少的坑,這裏大概列一下:
-
簽名用的 keystore 要位於
~/.keystore
-
若是項目依賴於 APK Library,如 ActionBarSherlock。請務必在
Build.scala
中將compileOrder
設定爲CompileOrder.JavaThenScala
-
Scala 對於 Java 7 的支持不好,所以如果系統中裝的是 JDK 7 以上版本,務必在
javacOptions
中加入Seq("-source", "1.6", "-target", "1.6")
Proguard
Android 上是沒有 Scala 標準庫的,但若是將所有 Scala 的庫都打包進 APK,體積上會非常驚人(>20MB)。因此 sbt-android-plugin
默認會對沒有用到的類和方法進行精簡。由於其規則過於激進,偶爾會發生代碼被裁減的問題。比如一個自定義的
View,且只在佈局文件中被使用,這時 Proguard 因無法從代碼中檢測到相關引用而會錯誤的將其裁減。因此建議你至少加入以下規則:
1 2 3 4 5 |
|