Android Studio 3.0+ 新Dex編譯器D8 Desugar R8

〇.序

將.class自己碼轉化為.dex字節(jié)碼作為Apk打包的關鍵步驟,Google打算在Android 3.0中引入D8作為原先Dex的升級版,以及R8作為原本Proguard 壓縮與優(yōu)化(minification、shrinking、optimization)部分的替代品。升級Dex編譯器將直接影響構建時間,.dex文件大小,運行時性能。

一.D8

1.1 D8 的功能是把java字節(jié)碼轉化成dex代碼,D8作為DX的一個替換方案。

谷歌通過自己的 基準測試項目測出,編譯時間縮短了20%,而且.dex文件更小,雖然只有幾個百分比。D8編譯的.dex文件將擁有相同或者是更好的運行時性能。

Dex編譯時間 DX VS D8
dex文件大小 DX VS D8

Java 8支持相關

Android Studio 3.0 及以上版本支持所有 Java 7 語言功能,以及部分 Java 8 語言功能(具體因平臺版本而異)。
注:在開發(fā) Android 應用時,可以選擇使用 Java 8 語言功能。 您可以將項目的源代碼和目標代碼兼容性值保留為 Java 7,但仍須使用 JDK 8 進行編譯。
Android Studio 為使用部分 Java 8 語言功能及利用這些功能的第三方庫提供內置支持。 如圖 1 所示,默認工具鏈對 javac 編譯器的輸出執(zhí)行字節(jié)碼轉換(稱為 desugar),從而實現(xiàn)新語言功能。 Jack 不再受支持,您需要首先停用 Jack 才能使用默認工具鏈內置的 Java 8 支持。

采用 desugar 字節(jié)碼轉換的 Java 8 語言功能支持。

目前Java 8語言支持的處理是在javac之后,與字節(jié)碼處理工具處理之前。在接下來的幾個月,這個步驟將會被移動到pipeline的后一個階段,作為D8的一部分。

其帶來的影響:

  • 減少這塊的編譯時間
  • 可以優(yōu)化更多代碼
  • 這么一來,所有字節(jié)碼處理工具就必須要支持Java8的字節(jié)碼格式了。

1.2 D8的使用

已經在Android Studio 3.0 Beta release中引入

  • Android Studio 3.0
    需要主動在gradle.properties文件中新增:android.enableD8=true
  • Android Studio 3.1或之后的版本
    在3.1或之后的版本D8將會被作為默認的Dex編譯器。如果遇到問題,你可以通過修改gradle.properties文件里的一個屬性恢復到DX android.enableD8=false
  • 除了其他好處外,使用D8還有一個好處,就是支持 脫糖,讓Java 8才提供的特性(如lambdas)可以轉換成Java 7特性。把脫糖步驟集成進D8影響了所有讀或寫.class字節(jié)碼的開發(fā)工具,因為它會使用Java 8格式。你可以在gradle文件中設置一個屬性,恢復到以前的行為,讓脫糖發(fā)生在Java編譯之后,.class字節(jié)碼仍遵循Java 7格式:android.enableD8.desugaring = true
D8 dexer

d8 dexer desuger

1.3脫糖(Desugar)

當我們選擇JDK8以上版本時,有時候會使用lambda表達式,在設置android.enableD8.desugaring = false的時候。編譯鏈會對lambda表達式進行一次脫糖處理。請看下面的例子。

1.3.1 純函數(shù)脫糖

源代碼很簡單:

一個簡單的Activity,設置ClickListener一種是Java7以下的傳統(tǒng)寫法,一種是Java8的Lambda表達式寫法

public class MainActivity extends Activity {

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView tv = findViewById(R.id.click);
    tv.setOnClickListener(view -> {
      Log.d("MainActivity", "MainActivity");
    });
    tv.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        Log.d("MainActivity", "MainActivity");
      }
    });

  }
}

編譯后的Class文件如下:

路徑為
app/build/intermediates/transforms/desugar/release(buildType)/0/com.jamin.d8desugar(packageName)/

desugar生成的class放置的位置

public class MainActivity extends Activity {

  public MainActivity() {
  }

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(2130968576);
    TextView tv = (TextView)this.findViewById(2130903040);
    tv.setOnClickListener(MainActivity$$Lambda$0.$instance);
    tv.setOnClickListener(new OnClickListener() {
      public void onClick(View view) {
        Log.d("MainActivity", "MainActivity");
      }
    });
  }
}
final class MainActivity$$Lambda$0 implements OnClickListener {
  static final OnClickListener $instance = new MainActivity$$Lambda$0();

  private MainActivity$$Lambda$0() {
  }

  public void onClick(View var1) {
    MainActivity.lambda$onCreate$0$MainActivity(var1);
  }
}

實際上非D8脫糖,為了保證JAVA7及以下的兼容性。是將lambda表達式的在javac編譯class的時候就已經將lambda表達式轉化成更高兼容度的低版本代碼。好處是在編譯鏈中,有時候會使用一些java7的工具。他們對于java8的語法糖是無法識別的。

1.3.2 非純函數(shù)脫糖

好,我們簡單改寫一下源文件

public class MainActivity extends Activity {

  String abc = "abc";

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView tv = findViewById(R.id.click);
    tv.setOnClickListener(view -> {
      Log.d("MainActivity", "MainActivity" + abc);
    });
    tv.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        Log.d("MainActivity", "MainActivity" + abc);
      }
    });
  }
}
生成的class文件如下:
public class MainActivity extends Activity {
  String abc = "abc";

  public MainActivity() {
  }

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(2130968576);
    TextView tv = (TextView)this.findViewById(2130903040);
    //注意this傳遞過去了。類似于內部類的寫法
    tv.setOnClickListener(new MainActivity$$Lambda$0(this));
    tv.setOnClickListener(new OnClickListener() {
      public void onClick(View view) {
        Log.d("MainActivity", "MainActivity" + MainActivity.this.abc);
      }
    });
  }
}
// $FF: synthetic class
final class MainActivity$$Lambda$0 implements OnClickListener {
  private final MainActivity arg$1;

  MainActivity$$Lambda$0(MainActivity var1) {
    this.arg$1 = var1;
  }

  public void onClick(View var1) {
    this.arg$1.lambda$onCreate$0$MainActivity(var1);
  }
}

此時生成的class文件就不是純函數(shù)了。所以會不會內存泄漏?

1.3.3 D8脫糖

在設置android.enableD8.desugaring = true的時候(高版本,比如AGP的版本是com.android.tools.build:gradle:3.3.0-alpha03時,默認是D8脫糖),D8脫糖就不會在transforms目錄下生成desugar目錄。反編譯transforms/dexBuilder/中的jar包??梢钥吹皆趈ar包中,已經是脫糖后的結果了。大家可以看下圖。也是把lambda表達式生成一個靜態(tài)對象。

MainActivity

Lambda

當然D8脫糖,要求編譯鏈中所有工具都支持java8,不然不認識class文件中的部分語法糖。D8脫糖的好處是什么呢。官方的話說就是可以提高編譯速度。

二.R8

R8作為原本Proguard 壓縮與優(yōu)化(minification、shrinking、optimization)部分的替代品,依然使用與Proguard一樣的keep規(guī)則。
目前R8已經開源: r8/r8,其包含了D8與R8。

目前R8還沒有整合進Android Gradle plugin,不過由于其已經開源,根據(jù)文檔可以很快的在python環(huán)境下運行起來:

  1. 確保本地已經安裝了python 2.7或更高版本(macOS Sierra自帶python 2.7)。
  2. 由于R8項目使用chromium項目提供的depot_tools管理依賴,因此先安裝depot_tools
  3. Clone R8項目:git clone https://r8.googlesource.com/r8 && cd r8
  4. 下載一個Gradle版去編譯,并且聲稱兩個jar文件: build/libs/d8.jar與build/libs/r8.jar: python tools/gradle.py d8 r8
    根據(jù)r8文檔進行使用即可

BREAKING NEWS:新版AndroidStudio可以體驗一下。

New code shrinker R8 is a new tool for code shrinking and obfuscation that replaces ProGuard. You can start using the preview version of R8 by including the following in your project’s gradle.properties file: android.enableR8 = true
官方文檔: New code shrinker

參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,789評論 25 709
  • Android 新一代編譯 toolchain Jack & Jill 簡介 2016 年 3 月 10 日, G...
    heiheiwanne閱讀 1,287評論 0 3
  • 我叫cimi,是人類社會為了區(qū)別我們,給予物質已命名已概念,對于我那個符號是:cimi;橘貓;豆芽的情人受;大力...
    feono閱讀 681評論 1 6
  • 時光如梭塵路不平,大多數(shù)人的每時每刻都在為生存而忙忙碌碌的奔波著,為生活而辛辛苦苦的操持著。 盡管在現(xiàn)實狀況里很多...
    大浪淘沙S6閱讀 373評論 0 1
  • “你買這么大的東西之前考慮過三輪車的感受嗎?”---今天一早我被快遞小哥在電話那頭這樣問到。 “那你送不了貨的話,...
    雜食的明子閱讀 665評論 0 0

友情鏈接更多精彩內容