Android中避免使用枚舉類(Enum)

如需轉載請評論或簡信,并注明出處,未經(jīng)允許不得轉載

目錄

前言

Android官方training文檔中有一句話

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android

http://www.androiddocs.com/training/articles/memory.html

枚舉類的好處

在java中,使用枚舉類可以保證類型安全提高代碼可讀性。無論需求如何變化求晶,比如枚舉常量增加一個數(shù)據(jù)崖蜜,或是增加一條狀態(tài)浊仆,都可以很方便的實現(xiàn),比直接在全局常量類里定義狀態(tài)來的便捷

static與Enum比較

  • 第一步:有一個Android Project豫领,編譯后生成的dex的體積為3,465,228byte

  • 第二步:新增創(chuàng)建一個類抡柿,如下所示,編譯后生成的dex的體積為3,465,532byte(比初始增加304byte

public class Test {
    public static final int RED = 1;
    public static final int BLACK = 2;
    public static final int GREEN = 3;
    public static final int YELLOW = 4;

    public int fun(int color) {
        switch (color) {
            case RED:
                return -1;
            case BLACK:
                return -2;
            case GREEN:
                return -3;
            case YELLOW:
                return -4;
            default:
                return 0;
        }
    }
}
  • 第三步等恐,改寫第二步中創(chuàng)建的類洲劣,如下所示,編譯后生成的dex的體積為3,466,568 byte(比初始增加1340byte课蔬,比使用static增加1036byte

初步結論:使用Enum會比static增加2-3倍的byte囱稽,從而增加apk的體積

Enum源碼分析

我們創(chuàng)建了一個枚舉類Color

public enum Color {
    RED, GREEN, BLACK, YELLOW
}

編譯項目,在app/build/intermediates/javac/debug/classes/項目名稱目錄下二跋,可以找到Color.class文件战惊,執(zhí)行javap -c Color.class命令對class文件進行反編譯,結果如下所示

Compiled from "Color.java"
public final class com.geekholt.kotlinandjavademo.Color extends java.lang.Enum<com.geekholt.kotlinandjavademo.Color> {
  public static final com.geekholt.kotlinandjavademo.Color RED;

  public static final com.geekholt.kotlinandjavademo.Color GREEN;

  public static final com.geekholt.kotlinandjavademo.Color BLACK;

  public static final com.geekholt.kotlinandjavademo.Color YELLOW;

  public static com.geekholt.kotlinandjavademo.Color[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[Lcom/geekholt/kotlinandjavademo/Color;
       3: invokevirtual #2                  // Method "[Lcom/geekholt/kotlinandjavademo/Color;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Lcom/geekholt/kotlinandjavademo/Color;"
       9: areturn

  public static com.geekholt.kotlinandjavademo.Color valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class com/geekholt/kotlinandjavademo/Color
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class com/geekholt/kotlinandjavademo/Color
       9: areturn

  static {};
    Code:
       0: new           #4                  // class com/geekholt/kotlinandjavademo/Color
       3: dup
       4: ldc           #7                  // String RED
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field RED:Lcom/geekholt/kotlinandjavademo/Color;
      13: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      16: dup
      17: ldc           #10                 // String GREEN
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field GREEN:Lcom/geekholt/kotlinandjavademo/Color;
      26: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      29: dup
      30: ldc           #12                 // String BLACK
      32: iconst_2
      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      36: putstatic     #13                 // Field BLACK:Lcom/geekholt/kotlinandjavademo/Color;
      39: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      42: dup
      43: ldc           #14                 // String YELLOW
      45: iconst_3
      46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      49: putstatic     #15                 // Field YELLOW:Lcom/geekholt/kotlinandjavademo/Color;
      52: iconst_4
      53: anewarray     #4                  // class com/geekholt/kotlinandjavademo/Color
      56: dup
      57: iconst_0
      58: getstatic     #9                  // Field RED:Lcom/geekholt/kotlinandjavademo/Color;
      61: aastore
      62: dup
      63: iconst_1
      64: getstatic     #11                 // Field GREEN:Lcom/geekholt/kotlinandjavademo/Color;
      67: aastore
      68: dup
      69: iconst_2
      70: getstatic     #13                 // Field BLACK:Lcom/geekholt/kotlinandjavademo/Color;
      73: aastore
      74: dup
      75: iconst_3
      76: getstatic     #15                 // Field YELLOW:Lcom/geekholt/kotlinandjavademo/Color;
      79: aastore
      80: putstatic     #1                  // Field $VALUES:[Lcom/geekholt/kotlinandjavademo/Color;
      83: return
}

把上面的字節(jié)碼文件翻譯成java大致如下所示

public final class Color extends java.lang.Enum<Color> {
    public static final Color RED;

    public static final Color GREEN;

    public static final Color BLACK;

    public static final Color YELLOW;

    static {
        RED = new Color("RED", 0);

        GREEN = new Color("GREEN", 1);

        BLACK = new Color("BLACK", 2);

        YELLOW = new Color("YELLOW", 3);

        VALUES = new Color[]{RED, GREEN, BLACK, YELLOW};
    }

    public static Color[] values() {
        Color tmp = new Color[VALUES.length];
        system.arraycopy(VALUES, 0, tmp, 0, VALUES.length);
        return tmp;
    }

    public static Color valueOf(String name) {
        return Enum.valueOf(name);
    }
}

由此我們可以得出以下結論:

  • Enum中的每一個值都是一個Object扎即,它的每個聲明都會占用運行時的部分內存以便能夠引用到這個Object吞获。因此Enum的值會比對應的IntegerString所占用的內存多
  • 很多時候我們聲明static變量只需要在已有的類中進行聲明,而如果使用枚舉類铺遂,就會多出一個類衫哥,最終則會增大Dex的體積,顯然Enum的空間占用是遠大于Integer常量或String常量的

解決方案

  1. 為了彌補 Android 平臺不建議使用枚舉的缺陷襟锐,官方推出了兩個注解撤逢,@IntDef@StringDef,用來提供編譯期的類型檢查
  • 添加依賴
    在build.gradle文件中的依賴塊中添加:
    dependencies { compile 'com.android.support:support-annotations:24.2.0' }

  • 聲明常量和@IntDef

    @IntDef({
          Color.RED,
          Color.GREEN,
          Color.BLACK,
          Color.YELLOW
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Color {
       int RED = 1;
       int GREEN = 2;
       int BLACK = 3;
       int YELLOW = 4;
    }
    

    這里@TypeDef注解使用了@interface來聲明新的枚舉注解類型粮坞。其中@IntDef@StringDef注解以及@Retention標注了新的注解蚊荣,目的是定義這個枚舉類型。而@Retentino(RententionPolicy.SOURCE)注解告訴編譯器在生成.class文件時不保留枚舉注解數(shù)據(jù)

  • 使用方法如下莫杈, 這樣外界就無法傳遞 Color 之外的成員作為參數(shù)

    public static void doSth(@Color int color){
       switch (color){
          case Color.RED:
              //do something
              break;
           case Color.GREEN:
              break;
           case Color.BLACK:
              break;
           case Color.YELLOW:
              break;
        }
    }
    
  1. 如果開啟了Proguard可以在很多情況下將枚舉Enum優(yōu)化到整數(shù)對象互例。

結論

在android中使用枚舉類不僅會增加apk體積,同時也會增加運行時內存筝闹,所以在架構設計上還是要慎用枚舉類媳叨。如果希望進行編譯期類型檢查可以使用@IntDef@StringDef類保證類型安全

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
禁止轉載腥光,如需轉載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末糊秆,一起剝皮案震驚了整個濱河市武福,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痘番,老刑警劉巖捉片,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汞舱,居然都是意外死亡伍纫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門昂芜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莹规,“玉大人,你說我怎么就攤上這事说铃》孟В” “怎么了嘹履?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵腻扇,是天一觀的道長。 經(jīng)常有香客問我砾嫉,道長幼苛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任焕刮,我火速辦了婚禮舶沿,結果婚禮上,老公的妹妹穿的比我還像新娘配并。我一直安慰自己括荡,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布溉旋。 她就那樣靜靜地躺著畸冲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪观腊。 梳的紋絲不亂的頭發(fā)上邑闲,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音梧油,去河邊找鬼苫耸。 笑死,一個胖子當著我的面吹牛儡陨,可吹牛的內容都是我干的褪子。 我是一名探鬼主播量淌,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嫌褪!你這毒婦竟也來了类少?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤渔扎,失蹤者是張志新(化名)和其女友劉穎硫狞,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晃痴,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡残吩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了倘核。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泣侮。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖紧唱,靈堂內的尸體忽然破棺而出活尊,到底是詐尸還是另有隱情,我是刑警寧澤漏益,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布蛹锰,位于F島的核電站,受9級特大地震影響绰疤,放射性物質發(fā)生泄漏铜犬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一轻庆、第九天 我趴在偏房一處隱蔽的房頂上張望癣猾。 院中可真熱鬧,春花似錦余爆、人聲如沸纷宇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽像捶。三九已至,卻和暖如春转捕,著一層夾襖步出監(jiān)牢的瞬間作岖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工五芝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痘儡,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓枢步,卻偏偏與公主長得像沉删,于是被迫代替她去往敵國和親渐尿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容