Android內存優化:用註解的方式替代枚舉

1. 問題起源

那天寫代碼的過程中,switch使用枚舉類作爲條件時,突然出現了一個報錯

枚舉 switch case 標籤必須爲枚舉常量的非限定名稱

public class UsbMsg {

    private MsgType mMsgType;

	// 這是我的枚舉
    public enum MsgType {
        MOUNT,
        UNMOUNT,
        BAD_REMOVAL,
        REMOVED
    }

	public MsgType getMsgType {
		return mMsgType;
	}
}

// 這是使用時的代碼
switch (usbMsg.getMsgType()) {
    case MsgType.MOUNT:  // 報錯行
    case MsgType.UNMOUNT: {
        showUsbList(volumes);
        break;
    }
}

[黑人問號臉.jpg] 這是哪兒錯了???一番百度之後發現,人家寫的很明白了,直接用enum裏面的名稱,把MsgType去掉,不用限定,因爲你的switch裏面已經限定是這個枚舉類裏面的值了!
後來就跟同事吐槽了一下,然後同事爲我打開了新世界大門,他說他一般不用枚舉,用註解的方式!仿照android原生VISIBLE/INVISIBLE/GONE的寫法!!高級了一下!

2. 爲什麼不使用枚舉?

找了一篇文章==>Android官方不建議使用枚舉的原因,大概原因就是因爲枚舉本身是一個類,編譯後會對每一種定義的類型生成相應對象,相對於靜態常量來講,消耗了很多內存。如果只是單純的想做類型限定的話,完全沒必要使用枚舉。

3. 如何使用註解替代枚舉?

下面我們來看一下,android原生是怎麼寫的?

    /** @hide */
    @IntDef({VISIBLE, INVISIBLE, GONE}) // Visibility的類型限定
    @Retention(RetentionPolicy.SOURCE) // 註解只存在於源碼編譯期
    public @interface Visibility {}

    /**
     * This view is visible.
     * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int VISIBLE = 0x00000000;

    /**
     * This view is invisible, but it still takes up space for layout purposes.
     * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int INVISIBLE = 0x00000004;

    /**
     * This view is invisible, and it doesn't take any space for layout
     * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
     * android:visibility}.
     */
    public static final int GONE = 0x00000008;

首先定義了幾個常量類型,之後定義了一個註解名爲Visibility,使用了兩個註解,@IntDef用來限定Visibility中int類型常量的值(默認情況下值不可重複,會有編譯報錯,若一定要重複如更新一個變量名,但又要保持向下兼容,就可以使用@SuppressLint(“UniqueConstants”)拒絕類型檢查),@Retention用來限定該註解存在於源碼時期,一般用來做一些源碼檢查操作。
在使用時,我們可以像下面一樣將註解加在參數上,這樣就可以像Enum一樣對參數進行類型限制。值得注意的是,這樣的類型檢查只會在編譯器中進行提醒,並不會影響編譯過程,如果你無視提醒直接運行那麼也是不會報錯的。

public void setVisibility(@Visibility int visibility) {
        setFlags(visibility, VISIBILITY_MASK);
}

那麼下面我們仿照Android原生的代碼修改一下之前的代碼,就會變成這樣

public class UsbMsg {

    private int mMsgType;

	// 這是我的註解
    @IntDef({MOUNT, UNMOUNT, BAD_REMOVAL, REMOVED})
    @Retention(RetentionPolicy.SOURCE)
    public @interface MsgType {
    }
    public static final int MOUNT = 0x0;
    public static final int UNMOUNT = 0x2;
    public static final int BAD_REMOVAL = 0x4;
    public static final int REMOVED = 0x8;

    @MsgType
    public int getMsgType() {
        return mMsgType;
    }

}

switch (usbMsg.getMsgType()) {
    case UsbMsg.MOUNT: {
        break;
    }
    case UsbMsg.UNMOUNT: {
        break;
    }
    default: {
        break;
    }
}

注意到@IntDef這個註解並不是默認提供的,是在support包中的,所以使用的話需要引入一下包compileOnly ‘com.android.support:support-annotations:28.0.0’,包版本根據你的compileSdkVersion來,另外他還有個好兄弟可以做String類型的限定 - @StringDef。最後查找資料過程中發現一個寫的不錯的文章,推薦下==>Android中不使用枚舉類(enum)替代爲@IntDef @StringDef

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章