Android 64K 方法 & MultiDex
OverView of Content
64K 方法
當 APP 開發到一定版本以後,必可避免的會遇到 APK 64K 方法數的問題,這個跟 Dex 虛擬機有
關係,這裡也會說明解決方案
64K 其實是方便記憶,其實限制數目為 2 Byte => 0xFFFF 也就是 65536
64K 方法 - 錯誤訊息
若 APP 中建構的方法數量 64K,則會在編譯的時候出現錯誤,導致 build 失敗,錯誤訊息如下
- 舊版本錯誤訊息
- 新版錯誤訊息
64K 限制原因
MultiDex
Android 5.0 之前 (API level 21)
- 在 Android 5.0 之前,全部的 dex 檔案都是透過 Dalvik 虛擬機來運行的,當方法數量超過 64K 時我們需要拆分 classes.dex 檔案 (將一個 classes.dex 檔拆成 classes.dex、classes2.dex、classes3.dex)
- 在啟動時會先加載 classed.dex 檔案 (classed.dex 檔案也稱為 Primary dex),之後才會加載其他 dex 檔案 (其他的稱為 Secondary dex)
Android 5.0 之前 - MultiDex 注意事項
-
應用啟動後會,Dalvik 虛擬機會執行 dexopt 的操作 (優化 dex 檔案),產生 ODEX 檔案,這個過程 複雜、耗時,若 dex 檔案過大則可能導致 ANR
-
由於 Dalvik 的線性記憶體分配器 LinearAlloc 的限制,使用 MultiDex 的應用在出現很大的記憶體分配時容易導致 App 當機,根本原因是 Dalvik 虛擬機用來載入類別的堆積記憶體大小被強制寫入
Android 版本 |
堆積記憶體大小 |
Android 2.3 以下 |
5M |
Android 2.3 |
8M |
Android 4.0 |
16M |
- Android 5.0 以上使用 ART,就不存在 LinearAlloc 限制問題 (除非你手動用 ClassLoader 加載)
- 由於存在 Primary、Secondary 兩種 dex 分類,所以還需區分那些類必須放置在 Primary dex (像是啟動 Application 類就要放置),若 ClassLoader 加載不到則會出現 NoClassDefFoundError 錯誤
Android 5.0 之後
- 從 Android 5.0 開始,Android 使用了 ART 虛擬機來代替 Dalvik 虛擬機,但並非捨棄了 dex 檔案,ART 虛擬機仍可載入 .dex 檔案
- ART 的特色是,在 APP 安裝期間會執行 預編譯 動作,掃描 APK 中的 全部的
.dex
檔案,並將它們編譯成 單一個 .oat
檔案,在應用執行期間去載入 .oat
檔案而不是 .dex
檔
- ART 不能在運行期間載入 dex 檔案 ?
ART 預設會先跑 oat 檔,但能是支持運行期加載 dex 檔案的,熱修復有其中一個方案就是採用自己透過 ClassLoader 加載 dex 檔案做修復
Android Module
- 每個 Android Module 都會對應到不同的 dex 檔案,有幾個 Module 就有幾個 dex 檔,通過這個點可以把主 dex 放置到主 Module 上,其他工具類放到別的 Module
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
解決方案
有個廢話就是~ 盡量減少方法,不讓其觸及 64K 的上限,這麼說是有原因的
因為在 APP 啟動時載入的 classes.dex 檔案若過多、過大,會導致啟動速度降低,並且可能導致 OOM 等等問題 (上面有提過)
gradle proguard 設定
- 可以透過 Gradle 的 proguard 設定,能套過分析位元組碼,壓縮並移除沒有使用到的函數,可以有效減少方法數量
專案開啟 MultiDex 設定
-
1 gradle#defaultConfig 設定 multiDexEnabled true,2 並使用 multidex Lib
-
自訂一個 Application,並對其設定(有兩種方案),1 繼承 MultiDexApplication、2 透過 MultiDex#install 初始化
- 為何使用在 attachBaseContext 方法
因為 attachBaseContext 方法在 onCreate 方法前執行
-
在 AndroidManifest.xml 設定自定義的 Application
Appendix & FAQ