相信一位有經(jīng)驗(yàn)的安卓開發(fā)人員,都會(huì)遇到過以下錯(cuò)誤<如果你還沒遇到類似情況,要么你是高手,要么就是你的開發(fā)經(jīng)驗(yàn)還沒到觸發(fā)這種情況的條件>
上圖中的錯(cuò)誤主要是由于我們打包后classes.dex文件里方法數(shù)量超出的65536個(gè)
Google官方文檔:https://developer.android.com/intl/zh-cn/tools/building/multidex.html
問題:那這個(gè)65536倒底是怎么計(jì)算的了?
有兩種說法
- 項(xiàng)目工程的方法總和<包括library>
- 方法引用次數(shù)的總和
第一種是目前大部分網(wǎng)上的說法;第二種是本人聽說的<但當(dāng)時(shí)很是疑惑>
1.項(xiàng)目工程的方法總和<包括library>
這種說法并沒有說錯(cuò),但不完全對,為什么了,如果你什么都不做的話,正常編譯打包確實(shí)是可以按照這種說法來進(jìn)行計(jì)算,但肯定我們還是可以做點(diǎn)什么的?<后話>
2.方法引用次數(shù)的總和
這種說法如果單獨(dú)拿出來講,基本是錯(cuò)的,為什么?
我們想想,引用次數(shù),也就是調(diào)用次數(shù),那意思是說,我只要調(diào)用方法的次數(shù)超出了65536次,那是不是就會(huì)報(bào)出65536的限制問題了了?
答:No,本人測試過;測試方法很簡單:
1.寫個(gè)方法;
2.然后用for循環(huán)<循環(huán)次數(shù)肯定是大于65536的>,每次循環(huán)調(diào)用同一個(gè)方法,編譯后,安然無樣;
3.for循環(huán)后我不死心,遞歸,編譯后,安然無樣,所以說這種說法站不穩(wěn)腳.
正確的計(jì)算方法
本人經(jīng)過各種測試,測試過程就不說了,得出了幾個(gè)結(jié)論
- 兩種說法單獨(dú)拿出來說都不算對
- 說法1比說法2要靠譜一點(diǎn)
- 兩種說法相結(jié)合,才算是完美的答案
下面分析情況來說明計(jì)算方法
關(guān)鍵:是否混淆
- 無混淆
當(dāng)你的工程在編譯的時(shí)候沒有采取任何混淆措施,那么計(jì)算方式參考說法1
- 有混淆
當(dāng)你的工程在編譯的時(shí)候采取了混淆措施,那么計(jì)算方式如果按說法2來講,并不對,應(yīng)該是:程序中被使用/調(diào)用的方法數(shù)量的總和
情景說明
看完上面后基本就說完了,但對于有混淆的情況時(shí),要知道幾點(diǎn)
情景一
有一個(gè)類 class A,里面有10個(gè)方法,但整個(gè)工程中用到了class A中的某一個(gè)方法,這時(shí)如果你的工程采用了混淆,那么class A中其余的9個(gè)方法并不會(huì)統(tǒng)計(jì)進(jìn)去
情景二
有一個(gè)接口 interface A,里面有10個(gè)方法,然后有一個(gè)實(shí)現(xiàn)類class B;如果你整個(gè)工程中是調(diào)用了class B里的某一個(gè)方法或某幾個(gè)方法,那么情況和<情景一>一樣,代碼是么寫的:
B b = new B();
b.xxx();
如果你是采用的多態(tài)的形式編寫的代碼,類似寫法:
A a = new B();
a.xxx();
那么方法數(shù)量是interface A 與 class B 里面被調(diào)用的那些方法之和,通俗的講就是調(diào)用的這個(gè)方法要當(dāng)兩個(gè)來計(jì)算
總結(jié)
- 用混淆來盡量讓64k的錯(cuò)誤晚點(diǎn)到來
- 少用多態(tài)的寫法來避免同一方法被重復(fù)核算
- 在不必要的情況下,盡量把邏輯寫在一個(gè)方法中
- 同樣的操作抽出成基類,在基類中統(tǒng)一實(shí)現(xiàn)
- 不要沒事就重寫父類的方法,主要表現(xiàn)在Activity與Fragment中的生命周期方法
- 如果你的app最低只兼容到4.0,Fragment就可以不用v4包中的
- 一句話:能不用兼容包的就不要用兼容包的,引入jar或library工程時(shí)注意下它們的方法數(shù)