性能優化一直都是一個 Android 開發者逃不過的話題,啓動優化則更是重中之重。啓動速度能夠直接影響一個 App 的留存率和轉化率,沒有人會但願本身點擊以後還要等一會纔打開。html
可是當我一番調研後發現,網上大部分啓動優化相關的文章,套路都差很少,我稱之爲老三樣。python
什麼是老三樣?linux
這麼作的目的主要是爲了消除啓動時的黑白屏,給用戶一種秒響應的感受,可是並不會真正減小用戶啓動時間,僅屬於視覺優化。android
1)經過減小冗餘或者嵌套佈局來下降視圖層次結構 2)用 ViewStub 替代在啓動過程當中不須要顯示的 UI 控件git
由於在主線程上進行資源初始化會下降啓動速度,因此能夠將沒必要要的資源初始化延遲,達到優化的效果。可是這裏要注意懶加載集中化的問題,別用戶啓動時間快了,可是沒法在界面上操做就尷尬了。github
老三樣並不說是無論用或者過期了,只是這三種優化方式都是很是基礎的方式,當你的啓動優化遇到了瓶頸,是不可以再經過這三種方式突破的。chrome
並且只會基礎的優化方式,並不會在履歷中展示出優點。shell
因此今天說說在老三樣的基礎優化之上還有哪些可行的方案。json
具體步驟xcode
1)清空手機後臺
2)在命令行執行
python $ANDROID_HOME/platform-tools/systrace/systrace.py gfx view wm am pm ss dalvik app sched -b 90960 -a 你的包名 -o test.log.html
複製代碼
這一步須要你係統環境配置了 ANDROID_HOME 環境變量。
3)運行你的App,正常操做到你想測性能的地方,而後再命令行窗口中按 Enter 鍵中止收集
4)用 chrome(只支持此瀏覽器)打開生成的 test.log.html 結果文件,打開效果以下圖:
目前須要關心地方就是咱們的應用進程相關的,也就是紅框圈起來的地方。
圖中的 F 表明繪製幀,黃色/紅色表示該幀繪製超時,綠色表明繪製正常,也就是在16.6ms內繪製完一幀。
關於 systrace 如何使用能夠參考這篇文章 性能工具Systrace
放大能夠看到在啓動過程當中,控件渲染耗時狀況
因此能夠很容易發現哪些啓動過程當中沒有用到的 UI 控件也被渲染了,這時就能夠用 ViewStub 去替代。
可是如今能夠看到的都是系統調用的耗時狀況,由於谷歌預先在代碼裏關鍵的地方加上了監控,若是想要看到本身方法的耗時,
那須要手動在方法入口加上 Trace.beginSection("TAG")
在方法結束的地方加上Trace.endSection()
這樣就能夠在生成的結果中看到咱們自定義的 tag。
若是不少地方你都想加上監控,手動加是確定不合適的,這裏推薦函數插樁方式自動加上監控代碼,參考 systrace+函數插樁
這種方式不只能夠幫助監控啓動過程當中性能問題,再作卡頓優化的時候也能夠用這種方式。
定位到了耗時方法,再作一些針對性的優化就相對容易了。
redex 是 Facebook 開源的一款字節碼優化工具,目前只支持 mac 和 linux。
咱們用的是裏面的 interdex 功能來重排列咱們 dex 中的 class 文件,那麼爲何重排列 class 文件能夠優化啓動速度?
簡單的說,經過文件重排列的目的,就是將啓動階段須要用到的文件在 APK 文件中排布在一塊兒,儘量的利用 Linux 文件系統的 pagecache 機制,用最少的磁盤 IO 次數,讀取儘量多的啓動階段須要的文件,減小 IO 開銷,從而達到提高啓動性能的目的。
具體能夠參考支付寶的這篇 《經過安裝包重排布優化 Android 端啓動性能》
因此咱們着手要作的就三件事:
1)安裝配置 redex 2)得到啓動過程當中 class 文件的加載順序 3)根據這個順序重排列 dex 中的 class 文件
具體步驟
1)下載 redex,配置環境(Mac OS)
git clone https://github.com/facebook/redex.git
xcode-select --install
brew install autoconf automake libtool python3
brew install boost jsoncpp
複製代碼
2)編譯安裝 redex
cd redex
autoreconf -ivf && ./configure && make
sudo make install
複製代碼
編譯時間較久,不想幹等着,能夠加上 say 指令,編譯完成後語音通知
autoreconf -ivf && ./configure && make && say '編譯完成'
3)配置優化項
由於 redex 默認不開啓 interdex,因此咱們要在配置文件中加上相應的配置,在 redex 文檔中有說明
因此咱們打開配置文件
cd redex/config/
vi default.config
複製代碼
按照下圖配置
4)得到啓動 class 加載順序列表
這裏按照 redex 提供的工具獲取,可是須要手機有 root 權限
首先清空後臺進程,而後打開你的應用
獲取你的應用的 pid
adb shell ps | grep 你的應用包名
複製代碼
收集堆內存,須要 root 權限
adb root
adb shell am dumpheap YOUR_PID /data/local/tmp/SOMEDUMP.hprof
複製代碼
把堆內存文件拉取到電腦的某個位置
adb pull /data/local/tmp/SOMEDUMP.hprof YOUR_DIR_HERE/.
複製代碼
經過 python 腳本解析堆內存,生成類加載順序列表
python redex/tools/hprof/dump_classes_from_hprof.py --hprof YOUR_DIR_HERE/SOMEDUMP.hprof > list_of_classes.txt
複製代碼
ps: 這個腳本支持 Python 2,執行過程當中若是遇到某個庫沒安裝之類的,直接經過 pip install 缺失的庫
就能夠
5)經過 redex 處理
ANDROID_SDK=你的Android sdk路徑 redex input.apk -o output.apk
複製代碼
6)從新簽名
這時候生成的 output.apk 是不能直接安裝的,須要從新簽名,我測試用的是 debug 包,因此從新簽了debug 的簽名
jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android output.apk androiddebugkey
複製代碼
到這就能夠從新安裝測試了,按照 facebook 的說法和一些大廠的實踐,啓動速度大概能夠提升 10%~20%,在低端機型上效果應該更明顯。
關於 redex 的使用和相關配置文檔,均可以在 redex/docs/ 目錄下查看。
爲了正確診斷冷啓動的性能,須要冷啓動的時間指標,下面有兩種簡單的方式:
adb命令 : adb shell am start -S -W 包名/啓動類的全名
例如:
adb shell am start -S -W com.android.helloword/com.android.helloword.MainActivity
複製代碼
這裏咱們關注 TotalTime 就能夠。
谷歌在 Android4.4(API 19)上也提供了測量方法,在 logcat 中過濾 Displayed 字段,
輸出的值表示在啓動過程和完成在屏幕上繪製相應 Activity 之間通過的時間,其實和上面的方式獲得的結果是同樣的。
關於 Android App 的冷啓動過程和一些概念能夠參考谷歌官方文檔 「App startup time 」
因爲一些緣由,還有一些優化方法沒有實踐,有興趣的能夠自行了解:
1)啓動過程當中的 GC 優化,儘可能減小 GC 次數,避免大量或者頻繁建立對象,如必須,可嘗試放到 Native 實現
2)線程優化,儘量減小 cpu 調度,具體就是控制線程數量和調度
3)在類加載的過程當中經過 Hook 去掉類驗證的過程,能夠在 systrace 生成的文件中看到 verifyClass 過程,由於須要校驗方法的每個指令,因此是一個比較耗時的操做
以上就是我關於 Android 冷啓動優化的一些總結,水平有限,不免出現不許確的地方,歡迎指正。
本文首發於公衆號「後知後jue」,微信搜索關注回覆「1024」,你懂的!