說到App優(yōu)化,首先考慮到的就是App啟動的優(yōu)化,要想加速啟動首先要先了解App啟動的過程。接下來我們首先簡要分析一下App冷啟動是怎樣一個流程。
應(yīng)用進(jìn)程不存在的情況下,從點(diǎn)擊桌面應(yīng)用圖標(biāo),到應(yīng)用啟動(冷啟動),大概會經(jīng)歷以下流程:
1.Launcher startActivity
2.AMS startActivity
3.Zygote fork 進(jìn)程
4.ActivityThread main()
4.1. ActivityThread attach
4.2. handleBindApplicatio
4.3. attachBaseContext
4.4. installContentProviders
4.5. Application onCreate
- ActivityThread 進(jìn)入loop循環(huán)
- Activity生命周期回調(diào),onCreate、onStart、onResume...
其中App能夠干預(yù)到的只有 4.3,4.5,6這三個步驟,其它的對App來說是黑盒的,App是不能控制的(除非設(shè)備Root,你可以干預(yù)其它流程,或者在設(shè)備啟動后直接后臺初始化自己的進(jìn)程), 我們的優(yōu)化也是主要針對這三個步驟進(jìn)行優(yōu)化。
1. attachBaseContext優(yōu)化
首先我們來看 attachBaseContext(),此方法我們一般會用作對多MultiDex做處理,我們知道Android5.0以前是不支持MultiDex的,需要在此方法中進(jìn)行
MultiDex.install(this) 安裝多dex,這個過程中會對我們的Apk進(jìn)行解壓縮找到dex文件列表,然后通過反射把dex文件放進(jìn)虛擬機(jī)ClassLoader中的dex數(shù)組中,這個過程因?yàn)橛薪鈮嚎sapk以及反射操作是比較耗時(shí)的。
既然這里是耗時(shí)的我們是否可以去開啟子線程去執(zhí)行MultiDex.install(),答案是否定的,假設(shè)一個場景,我們開線程異步加載,主線程繼續(xù)執(zhí)行后面的初始化ContentProviders或者 Application的onCreate()方法中如果有需要用到非主dex文件的Class而這時(shí)候子線程的MultiDex.install()還沒有完成安裝就會造成 NoClassDeFound異常,所以此方法是行不通的。具體優(yōu)化方案見:https://www.cnblogs.com/renhui/p/11716975.html
總結(jié):MulitiDex.install主要針對5.0以下的設(shè)備(不包含5.0),目前市面上的設(shè)備基本上已經(jīng)沒有5.0以下的設(shè)備了,所以這部分優(yōu)化能涵蓋的設(shè)備已經(jīng)很少了,5.0以上是默認(rèn)支持MulitdDex的,這個方法什么都不用做,直接返回。

2. Application onCreate()優(yōu)化
終于到了我們喜聞樂見的onCreate了,這一步也是我們優(yōu)化的主要戰(zhàn)場,通常在這一步中我們會做一些三方sdk以及自有業(yè)務(wù)的一些初始化,這些初始化工作其實(shí)并不是一開始就需要的,我們完全可以做一些懶加載處理或者異步加載。那怎樣判斷Application onCreate()方法的執(zhí)行耗時(shí)呢?
最Low的辦法就是在onCreate的方法入口 和 方法出口各自加時(shí)間戳判斷,但是這只能判斷整個方法的執(zhí)行時(shí)間,但假如我們的onCreate的方法中有很多個sdk要初始化呢,只能是每個sdk初始化前后各需要加時(shí)間戳判斷,這樣寫起來就太費(fèi)勁了。還好Android給我們提供了很多性能測試的方法。接下來我們介紹一下 Debug.startMethodTracing()與Debug.stopMethodTracing(),把這個方法加入Application的onCreate方法開始和結(jié)束處會默認(rèn)生成每個方法的堆棧信息及調(diào)用時(shí)間文件保存到sd卡中,然后再通過AS的 profile工具來查看詳細(xì)信息。
代碼如下:
@Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("im_ana");
initIm();// 初始化Im SDK
Debug.stopMethodTracing();
}
startMethodTracing()的參數(shù)是生成堆棧信息的文件名,擴(kuò)展名為.trace,生的文件會保存在 sdcard/Android/data/{$packageName}/file/ 目錄下。(注意:這里因?yàn)橐獙d卡讀寫需要先授權(quán),還有另外一個問題,堆棧文件信息默認(rèn)大小為10M,如果中間需要監(jiān)控的方法太多會導(dǎo)致信息收集不全,這時(shí)候可以在startMethodTracing()方法中配置堆棧文件的bufferSize處理)。把生成的文件導(dǎo)出來直接拖到AndroidStudio中即可以顯示可視化的方法堆棧信息。見下圖:

這里可以看到方法的調(diào)用堆棧以及每個方法的調(diào)用時(shí)間,有了這些信息,我們就可以輕松判斷到底是哪些方法執(zhí)行時(shí)間過長了。就可以選擇哪些需要開啟線程異步加載或者懶加載執(zhí)行了,目前Application的onCreate()優(yōu)化方法介紹完成了,如果有哪里寫的不對還請看到的大神指出來,感激不盡!
3. 首屏Activity優(yōu)化
3.1 首屏主題優(yōu)化
一般我們冷啟動App時(shí),首屏Activity首先會彈出來然后黑屏或白屏一段時(shí)間這段時(shí)間其實(shí)是在執(zhí)行上面說到的啟動流程。系統(tǒng)默認(rèn)給我們設(shè)置的主題樣式,既然是主題樣式我們就可以替換首屏Activity的主題來替換黑白屏,自定義主題樣式如下:
<style name="AppTheme.Loading" parent="AppTheme.NoActionBar">
<item name="android:windowBackground">@drawable/loading_fix</item>
<item name="android:windowFullscreen">true</item>
</style>
在windowBackground中設(shè)置drawable可以是我們自己的圖片,這樣就可以啟動時(shí)顯示我們配置的圖片信息,防止黑白屏的尷尬。
這里并沒有提高我們App的啟動時(shí)間,只是在體驗(yàn)是做了優(yōu)化。
3.2 布局文件加載優(yōu)化
布局文件加載要盡量減少層級,能用FrameLayout或者LinearLayout完成的就不要用RelativeLayout或者ConstraintLayout,因?yàn)镽elativeLayout會執(zhí)行兩次measure測量。還要合理運(yùn)用include,merge,ViewStub 來進(jìn)行層級縮減或懶加載來提高頁面渲染速度。
我們知道Android布局文件是能過讀取xml資源文件,然后通過反射生成Android的View這中間有兩個步驟是耗時(shí)操作,一個是讀取xml進(jìn)行的IO操作,一個是反射生成View的操作,這兩個步驟都是在運(yùn)行時(shí)同步的操作,這兩個流程都有可能造成性能方面的問題。針對此問題目前有三方解決方案 X2C ,其原理是通過apt工具在編譯期把xml布局文件生成 Java類。X2C開源庫地址:https://github.com/iReaderAndroid/X2C
3.剩下的問題就是不要在生命周期方法中執(zhí)行耗時(shí)操作,這樣會導(dǎo)致UI掉幀及ANR的問題。