Android 中不該該使用 Enum 嗎?

和作 Android 的同窗們提起 Enum(枚舉),不少人應該就會想到:「在 Android 中不要使用枚舉,會佔用更多的內存,應該使用註解代替」 這句話。若是你對此很不解並且保持懷疑態度,而後在 Google 上面一搜,就像下面圖中所示。 數組

嗯,果真如此,你們都說 Android 中不該該使用 Enum,並且官方文檔上也寫出不該該使用 Enum,好那我就不用了,改爲 Android 註解。而後這句好就被一傳十,十傳百,全部人都記住了 「 Android 中不推薦使用枚舉,請使用註解代替」。

而後事實真的是這樣嗎?到 2019 年的今天,每一步 Android 手機都擁有了 6G 或更大的內存,那麼這句 「 Android 中不推薦使用枚舉」 還適用嗎?微信

歷史背景

不少人相信且毫無疑問的相信,大概就是由於官方文檔上面寫的這句話吧。 網絡

「枚舉一般會比靜態常量多兩倍以上的內存佔用,因此你應該應該的避免在 Android 中使用枚舉」

沒錯這句話確實存在過,它出自 2009 年的 Android 官方文檔,當時 Android 處於剛剛起步的階段,受當時手機硬件設備的影響,Android 核心開發人員在文檔上寫下來這句話,在當時看來確實沒錯,而後現在十年後,咱們在 2019 年的 Android 官方文檔上,卻再也找不到這句話了,根據 stackoverflow 上面的回答,應該是 Android 團隊在發佈 Android P 以後修改掉了這句話。app

同時我查到了 JakeWharton 關於 Android 中使用枚舉的一些建議:函數

這裏的大概意思是,JW 認爲 ProGuard 和 R8 會在編譯的時候會將瑣碎的枚舉優化爲整型,不存在效率低下的問題,enum 效率低下只是 Android 團隊散佈的謠言,同時 Kotlin 和 Java 中的 Enum 在編譯成字節碼以後是同樣的。優化

在 Reddit 上,JW 一樣作出了迴應:編碼

有人提出質疑說,官方文檔上面的那句話是不正確的,具備誤導性,應該是當你把枚舉單純的當作 IntDef 使用的時候,會有內存上面的開銷。spa

JW 迴應到:咱們都忽略了 Enum 是一個完整類的事實,它能夠實現接口,能夠實現本身的方法,當你沒有這麼作的時候,ProGuard 會將枚舉優化爲整數,當時開發人員的這個建議徹底是錯誤的,一直以來都是錯誤的。翻譯

其實枚舉沒有那麼恐怖

enum class Type { ONE, TWO }
複製代碼

當咱們定義了這樣一個簡單的枚舉,反編譯代碼後,咱們會發現下面這樣的代碼:code

public final class MainActivity$WhenMappings {
public static final int[] $EnumSwitchMapping$0 = new int[Type.values().length];
	static {
		$EnumSwitchMapping$0[Type.ONE.ordinal()] = 1;
		$EnumSwitchMapping$0[Type.TWO.ordinal()] = 2;
	}
}
複製代碼

編譯器會幫咱們將枚舉優化爲一個 int 數組,這個是自動優化的,但前提是正如 JW 所說咱們只簡單的使用了枚舉中定義的字段,而沒有把它當作一個完整類來使用,調用它自身的一些方法,例如 toString() ,name 等。

而相反你若是使用註解來實現:

const val ONE = 1
const val TWO = 2
@IntDef(ONE, TWO)
@Retention(AnnotationRetention.SOURCE)
annotation class Type
複製代碼

其實這樣的優化是得不償失的,在必定程度上失去的代碼的可維護性,並且在 Kotlin 中對此寫法的支持也不是很好,咱們應該將關注力放在其餘投入產出比更大的事情上面。

更多的時候咱們不須要過度關心使用 Enum 帶來的內存增加,你要記住 Enum 是一個類,它只是佔用了做爲一個類來講應有的內存。

也許你會從以前的 Android SDK 中發現,官方的代碼中會有不少使用諸如 @IntDef 來替代 Enum,但我最近翻閱 Android Jetpack 中的相關代碼,官方開發人員也會在代碼中大量使用 Enum,例如 Lifecycle:

在 Kotlin 中更好的使用 Enum

在 Koltin 中除了 Enum 以外(和 Java 中的 Enum 沒什麼區別),還有 Sealed Class 能夠幫助咱們使用一樣的功能,Sealed Class 翻譯過來叫密封類。

密封類用來表示受限的類繼承結構:當一個值爲有限幾種的類型、而不能有任何其餘類型時。在某種意義上,他們是枚舉類的擴展:枚舉類型的值集合也是受限的,但每一個枚舉常量只存在一個實例,而密封類的一個子類能夠有可包含狀態的多個實例。

關於使用密封類有幾點注意事項:

  1. 須要在類名前面添加 sealed 修飾符
  2. 全部子類都必須在與密封類自身相同的文件中聲明
  3. 密封類是自身抽象的
  4. 密封類不容許有非-private 構造函數

一個很常見的使用場景,就是使用 Sealed Class 來聲明網絡請求狀態

更多關於 Sealed Class 的使用方法你們去看 Kotlin 的官方文檔就能夠了,很簡單,這裏就不贅述了。

因此關於 Enum 的使用,個人觀點是:該用就用,不須要去過度擔憂內存的增加,Enum 有不少方便好用的特性,Enum 帶來的編碼的便捷,代碼可讀性的提高也是很大的利好。

若是以爲這篇文章有點意思,記得分享轉發😝。

歡迎關注同名微信公衆號【Android丨Kotlin】

相關文章
相關標籤/搜索