在 Android N 預覽版中使用 Java 8 的新特性

Android團隊最近發布了Android N Preview,帶來了很多提升,包括由Jack編譯器提供的Java 8支持。在這篇文章中,我們將來看看它究竟對Android開發者意味著什么,以及如何嘗試新的語言特性。

免責聲明: 本信息在2016年3月30日是有效的,我不確定在下個release版本中,Google團隊會增加什么新的沒有在此提到的Java 8特性。

 

概覽

在這篇文章中,去介紹Oracle Java 8的新特性并沒有太大意義 —— 很多信息已經在互聯網上有了。我個人最喜歡的是Simon Ritter的“Java SE 8的55個新特性[2]”。

另一方面,Android 官方的Java 8公告[3] 留下了很多開放的問題給開發者們,感覺上并非所有的原生 Java 8 功能都是可用的。更詳細的 技術公告[4] 確認了這一點。我們可以根據在 Android N 中的可用性,將這些語言特性分類如下:

Android Gingebread (API 9)及以上:

Android N及以上:

所以對Java 8特性和使用的minSdkVersion之間的關聯性,開發者必須去精心選擇。我們也必須注意到語言向后兼容是由Jack編譯器提供的。在概念上,Jack編譯器將javac,ProGuard,以及dex的功能 合并 [5]到了一個轉換步驟中。這意味著[6]其中沒有中間的Java字節碼可用,且像是JaCoCo和Mockito的工具將無法工作,DexGuard也一樣 (ProGuard的企業版本)。讓我們祈禱這只是一個早期的preview版本,且這些問題將在未來被修復。

Lambda表達式以及相關的函數功能APIs —— 這是一個每個Android開發都會喜歡的東西。這類功能將會對增加代碼可讀性極為有用 —— 它替代了提供事件監聽器的匿名內部類。而之前只能通過額外的工具[7] 來實現,或者由Android Studio編輯器去折疊代碼。

默認及靜態interface方法可以幫助我們減少額外的工具類的數量,但顯然不是最需要的特性。還有一些其他的新增功能,我希望去說的更詳細一些,因此不在本文的范圍內。

對我來說最有趣的事 ——?Java 8 流(Streams) —— 在當前的預覽版中不可用。我們可以發現事實上它 剛被merge[8] 到AOSP源碼,所以期望可以在下個N Preview 或者 Beta release中見到它。如果你實在等不及去瀏覽 —— 可以試試使用 Lightweight-Stream-API[9],目前的一個開源向后兼容。

示例項目

官方手冊[10]提供了指示,甚至還有圖展示了如何去配置你的項目使用 Android N Preview 和 Java 8。在這兒沒什么可以再說的,就跟著指示走吧。

下一步是去配置你的app模塊的 build.gradle 文件。你可以在下面看到實例的 build.gradle 文件。從N SDK上的公告來看,似乎可以設置 minSdkVersion 為 Jelly Bean 或者 KitKat。 但… 在將targetSdkVersion 設為Android N Preview后,將無法工作在API低于N的設備上[11]。另外,如果你把 minSdkVersion 設置為23或者更低 —— Java 8代碼將無法編譯。這里是一些在 SO forums[12]的hack,描述了怎么設置minSdk為想要的值并使得app可以工作。我希望你不會在生產代碼中使用這種方法 :)

我決定保持實例代碼干凈,所以沒有添加任何hack手段來做低版本兼容,請讀者自由去嘗試或者使用N的測試設備/模擬器。

android {
    compileSdkVersion 'android-N'
    buildToolsVersion '24.0.0 rc1'

    defaultConfig {
        applicationId "org.sergiiz.thermometer"
        minSdkVersion 'N' // 在 N Preview 中不能使用低于N的版本
        targetSdkVersion 'N'
        versionCode 1
        versionName "1.0"
        jackOptions{
            enabled true
        }
    }
    compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
    }
    //...
}


所以來試著實現一些Java 8的優雅代碼到我們陳舊的Thermometer項目。請注意這個設置是跟著新的文檔[13]來的,使用了新的 Gradle DSL 方法 jackOptions 來配置Jack編譯器設置,在更老的版本中,我們使用 useJack true 來達到同樣的結果。

這是一個接口,包含了默認方法:

public interface Thermometer {

   void setCelsius(final float celsiusValue);

   float getValue();

   String getSign();

   default String getFormattedValue(){
      return String.format(Locale.getDefault(),
            "The temperature is %.2f %s", getValue(), getSign());
   }
}

實現了這個接口的類:

public class FahrenheitThermometer implements Thermometer {

   private float fahrenheitDeg;

   public FahrenheitThermometer(float celsius) {
      setCelsius(celsius);
   }

   @Override
   public void setCelsius(float celsius) {
      fahrenheitDeg = celsius * 9 / 5 + 32f;
   }

   @Override
   public float getValue() {
      return fahrenheitDeg;
   }

   @Override
   public String getSign() {
      return Constants.DEGREE + "F";
   }
}

增加一個點擊事件的lambda函數:

buttonFahrenheit.setOnClickListener(view1 -> {
   fahrenheitThermometer.setCelsius(currentCelsius);
   String text = fahrenheitThermometer.getFormattedValue();
   makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
});

例子的完整源碼可見 GitHub repository[14]

總結

在這篇文章中,我們了解了Java 8的用例,以及目前其在Android N Preview SDK的實現情況。我們也看到了當前Jack編譯器的限制,及其在最后發布前可能被修復的功能。在demo項目中我們檢驗了如何去使用新的Java 8特性,以及它們可以被應用的target SDK版本。

 本文由用戶 TamieBriley 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!