enum、static final 與 IntDef:Android 中實現枚舉的方案選擇

前述

曾經有一段時間,許多網上的 Android 性能調優的文章都提到,要儘可能避免在 Android 中使用 enum,由於使用 enum 會引入較大的性能損失。html

然而,最新的 Android 文檔已經改變了這一說法。根據 Android VM 的開發者Elliot Hugues 的博客所述,過去的 Android 官網的性能優化指南並不許確,混雜了許多臆斷。所以現在他們嚴格地依據事實,重寫了Android 性能優化指南,開發者也應當以最新的文檔爲準。固然比較窘迫的是,Android 文檔的更新並非同時改口,事實上就在同個 training 目錄下的 管理應用內存一文中,就仍然保留了過期的避免使用 enum 的說法。java

最新的解釋

之因此從新鼓勵使用 enum ,其解釋是:android

  1. Android 2.2 及如下系統上,使用 enum 的確會引起較大的性能損耗。主要是內存上的消耗,enum 遠大於使用 static final int。安全

  2. 在 Android 2.3 及之後的系統中,以前的一些 enum 的性能問題已被 JIT 所優化。此時,雖然 enum 相比於 static final int,內存仍然有所增長,但已是能夠接受的了。加之 Android 2.2 到現在的 Android 7.0,Android 手機的內存配置日新月異,從256MB躍升至6GB,enum 所帶來的內存增長已經能夠忽略。性能優化

強內存依賴的應用的枚舉實現

儘管如此,在實際開發中仍然有可能遇到內存消耗較大的應用開發問題,那麼此時,該如何優化枚舉值的實現,以節約內存消耗呢?方案以下:ide

直接使用 static final int

然而,其問題在於,直接使用沒法實現枚舉變量賦值的類型安全。且沒法把多個枚舉值概括到同一個枚舉類型下。好比:性能

private static final int MONDAY = 0;
private static final int TUESDAT= 1;
private static final int WEDNESDAY = 2;
private static final int THURSDAY = 3;
private static final int FRIDAY = 4;
private static final int SATURDAY = 5;
private static final int SUNDAY = 6;

private static final int JANUARY = 7;

private int day = JANUARY;

顯然,此時 int 就未能實現賦值的類型檢查,也未能把多個枚舉值概括到同一個枚舉類型下。優化

Android Proguard 優化

在 Android Proguard 中,能夠在 proguard.cfg 中加入參數 -Doptimization class/unboxing/enum,從而自動將 enum 替換爲 static final int。這樣,也就無需擔憂多餘的內存問題了。this

使用 IntDef 註解替代 int

IntDef 能夠用於替代 int,其價值在於用@IntDef int var限定賦值範圍,實現類型安全。還用 @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})歸集了散亂的 static final int 變量,以下代碼所示:code

public class MainActivity extends Activity {
 
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
 
    @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface WeekDays {}
 
    @WeekDays int currentDay = SUNDAY;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setCurrentDay(WEDNESDAY);
 
        @WeekDays int today = getCurrentDay();
 
        switch (today){
            case SUNDAY:
                break;
            case MONDAY:
                break;
            case TUESDAY:
                break;
            case WEDNESDAY:
                break;
            case THURSDAY:
                break;
            case FRIDAY:
                break;
            case SATURDAY:
                break;
            default:
                break;
        }
 
    }
 
    public void setCurrentDay(@WeekDays int currentDay) {
        this.currentDay = currentDay;
    }
 
    @WeekDays
    public int getCurrentDay() {
        return currentDay;
    }
}

然而,IntDef 的缺點在於沒法優雅地把 int 轉爲 IntDef,尤爲在一個枚舉值是服務端下發的時候。強行的實現會變的極爲尷尬:

@WeekDays
public int getDay(int value) {
        switch (value){
            case 0:
                return SUNDAY;
            case 1:
                return MONDAY;
            case 2:
                return TUESDAY;
            case 3:
                return WEDNESDAY;
            case 4:
                return THURSDAY;
            case 5:
                return FRIDAY;
            case 6:
               return SATURDAY;
}

此時,在枚舉值較少的時候還能忍,較多的時候代碼就會變得很是醜陋。本質是由於,@IntDef 缺乏像 Enum.values() Enum.ordinal() 等等 int 與 enum 與 String 互轉的方法,所以在想換轉換較多的場景下,不如採起第二種優化方法。

====================================

若是您以爲個人文章對您有所啓迪,請點擊文末的推薦按鈕,您的鼓勵將會成爲我堅持寫做的莫大激勵。 by DesGemini

相關文章
相關標籤/搜索