在項目開發(fā)中,在需要定義多個常量的開發(fā)場景(如上傳文件邏輯的狀態(tài)回調(diào))贴谎,會猶豫是應(yīng)該使用Enum枚舉還是直接定義Constants常量來解決問題。
查看 Google Developer Guide, 有提到
Avoid enumerations
A single enum can add about 1.0 to 1.4 KB of size to your app'sclasses.dex
file. These additions can quickly accumulate for complex systems or shared libraries. If possible, consider using the@IntDef
annotation and ProGuardto strip enumerations out and convert them to integers. This type conversion preserves all of the type safety benefits of enums.
避免使用枚舉類型
增加一個枚舉類能夠增加你應(yīng)用的classes.dex
文件大約1到1.4KB的大小季稳。建議使用@IntDef
annotation擅这。
那么到正式項目中,
- 在使用混淆的情況下增加一個枚舉具體會對APK增加多大的大芯笆蟆仲翎?
- 如果只創(chuàng)建一個枚舉類,增加枚舉中成員的個數(shù)铛漓,對
classes.dex
的影響有多大溯香? - 添加一個枚舉類,到底增加了哪些代碼浓恶?
- 在實際開發(fā)中玫坛,到底應(yīng)不應(yīng)該使用枚舉類代替常量的定義?
- 對需要定義多個常量的開發(fā)場景包晰,應(yīng)該如果編寫代碼湿镀?
帶著上面的問題,通過測試工程伐憾,一一解答勉痴。
一、在使用混淆的情況下增加一個枚舉具體增加多大的大腥蚀腿?
1、 通過Android Studio創(chuàng)建一個默認(rèn)項目扫外,解壓獲取classes.dex
文件莉钙,大小為1342700bytes,如下圖:
2筛谚、 添加一個常量類磁玉,在代碼中進(jìn)行引用,增加代碼如下:
// 常量類
public class Apple {
public static final int FIRST = 1;
public static final int SECOND = 2;
public static final int THREE = 3;
public static final int FOUR = 4;
public static final int FIVE = 5;
}
// MainActivity.class
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
Log.d("s", Apple.FIRST.toString())
}
重新獲取classes.dex
文件驾讲,大小為1342720bytes蚊伞,如下圖:
相對原始項目: 增加20bytes
大小席赂,影響非常小。
3时迫、添加一個只有一個元素的枚舉類颅停,在代碼中引用,另外刪除掉上面常量類代碼掠拳,增加代碼如下:
enum Apple {
FIRST
}
// 引用如上面的代碼癞揉,此處省略
重新獲取classes.dex
文件,大小為1343128bytes溺欧,如下圖:
相對原始項目: 增加
428bytes
大小喊熟,是增加一個常量類增加classes.dex
文件大小的21.4
倍
結(jié)論一: 在有混淆的情況下,增加一個枚舉類姐刁,classes.dex
文件大約增加0.5KB的大小芥牌。
二、如果只創(chuàng)建一個枚舉類聂使,增加枚舉中成員的個數(shù)壁拉,對classes.dex
的影響有多大?
1岩遗、 在1.3的基礎(chǔ)上扇商,對Apple
枚舉類中多添加幾個元素,代碼如下:
enum Apple {
FIRST,
SECOND,
THREE,
FOUR,
FIVE,
}
// 引用如上面的代碼宿礁,此處省略
重新獲取classes.dex
文件案铺,大小為134332bytes,如下圖:
相對于只有一個元素的枚舉類:增加204bytes
梆靖,平均每增加一個增加50bytes
控汉。
結(jié)論二: 如果已經(jīng)存在一個枚舉類,向其中返吻,每增加一個元素姑子,大約增加50bytes,影響并不很大测僵。
三街佑、添加一個枚舉類,到底增加了哪些代碼捍靠?
那么沐旨,增加一個枚舉類,到底增加了哪些元素榨婆?通過反編譯APK文件磁携,我們能夠獲取到其中的答案。
通過Android Studio
自帶的apk compare
工具良风,我們可以知道谊迄,每增加一個枚舉闷供,在classes.dex
中多增加1個class,增加4個method
,那么增加了什么類统诺,增加了哪些方法歪脏?
通過反編譯,貼出關(guān)鍵代碼如下:
.class final enum Lcom/learn/enumtest/a;
.super Ljava/lang/Enum;
# annotations
.annotation system Ldalvik/annotation/Signature;
value = {
"Ljava/lang/Enum<",
"Lcom/learn/enumtest/a;",
">;"
}
.end annotation
# static fields
.field public static final enum a:Lcom/learn/enumtest/a;
.field public static final enum b:Lcom/learn/enumtest/a;
.field public static final enum c:Lcom/learn/enumtest/a;
.field public static final enum d:Lcom/learn/enumtest/a;
.field public static final enum e:Lcom/learn/enumtest/a;
.field private static final synthetic f:[Lcom/learn/enumtest/a;
# direct methods
.method static constructor <clinit>()V
.locals 7
new-instance v0, Lcom/learn/enumtest/a;
const-string v1, "FIRST"
const/4 v2, 0x0
const-string v1, "SECOND"
const/4 v3, 0x1
const-string v1, "THREE"
const/4 v4, 0x2
const-string v1, "FOUR"
const/4 v5, 0x3
const-string v1, "FIVE"
return-void
// 省略掉其中部分代碼
.end method
.method private constructor <init>(Ljava/lang/String;I)V
.locals 0
.annotation system Ldalvik/annotation/Signature;
value = {
"()V"
}
.end annotation
invoke-direct {p0, p1, p2}, Ljava/lang/Enum;-><init>(Ljava/lang/String;I)V
return-void
.end method
.method public static valueOf(Ljava/lang/String;)Lcom/learn/enumtest/a;
.locals 1
const-class v0, Lcom/learn/enumtest/a;
invoke-static {v0, p0}, Ljava/lang/Enum;->valueOf(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
move-result-object p0
check-cast p0, Lcom/learn/enumtest/a;
return-object p0
.end method
.method public static values()[Lcom/learn/enumtest/a;
.locals 1
sget-object v0, Lcom/learn/enumtest/a;->f:[Lcom/learn/enumtest/a;
invoke-virtual {v0}, [Lcom/learn/enumtest/a;->clone()Ljava/lang/Object;
move-result-object v0
check-cast v0, [Lcom/learn/enumtest/a;
return-object v0
.end method
從反編譯代碼中粮呢,每增加一個枚舉類唾糯,無論是單獨(dú)的枚舉,還是內(nèi)部嵌套枚舉鬼贱,都會向classes.dex
文件中新增加一個java類,類中增加兩個構(gòu)造函數(shù)香璃,增加一個valueof函數(shù)这难,增加一個values函數(shù)
結(jié)論三: 添加一個枚舉,在程序編譯期葡秒,會自動增加有兩個構(gòu)造函數(shù)的Java類姻乓,同時生成values、valueof兩個函數(shù)眯牧,方便程序的調(diào)用蹋岩。
四、 在實際開發(fā)中学少,到底應(yīng)不應(yīng)該使用枚舉類代替常量的定義剪个?
通過上述比較,我們可以得出結(jié)論版确,使用枚舉對classes.dex
文件大小的影響扣囊,是直接定義常量的21.4倍,所以為了APK包的大小绒疗,盡力少使用枚舉侵歇,除非在需要常量與資源對應(yīng)的情況下。
五吓蘑、 對需要定義多個常量的開發(fā)場景惕虑,應(yīng)該如果編寫代碼?
推薦使用@intDef
,代碼如下:
public class Apple {
@IntDef({FIRST, SECOND, THREE, FOUR, FIVE})
public @interface State {
FIRST = 0;
SECOND = 1;
THREE = 2;
FOUR = 3;
FIVE = 4;
}
private int mState;
public void setState(@State int state) {
mState = state;
}
@State
public int getState() {
return mSate;
}
}
@interface
注解修飾State
,不需要在寫public static final int
進(jìn)行修飾磨镶,@IntDef
注解定義State
都包含哪些值溃蔫,如果不在取值范圍內(nèi),在編譯期會報紅提醒棋嘲,防止setState
被隨便設(shè)置參數(shù)的問題酒唉,代替枚舉優(yōu)勢,同時對APK包大小的增加非常小沸移。
枚舉和常量的比較痪伦,就寫到這里侄榴,如果有任何問題,歡迎留言网沾。