今天跟大家聊一聊,一個(gè)android app啟動(dòng)過(guò)程,有哪些方法可以加快啟動(dòng)速度。
先來(lái)說(shuō)一說(shuō)有哪些因素可能會(huì)延緩啟動(dòng)速度:
1.UI線程IO操作(數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)、SharePreference、文件讀寫、磁盤操作、文件夾創(chuàng)建等)
UI線程是Android中負(fù)責(zé)渲染視圖的線程,也是Android四大組建生命周期回調(diào)的主要執(zhí)行線程,還是用戶交互事件的主要響應(yīng)線程,所以UI線程任務(wù)繁重。
IO操作容易阻塞,且容易受出現(xiàn)不穩(wěn)定狀況,存在各種潛在威脅。
2.靜態(tài)類中的靜態(tài)變量初始化
一個(gè)類中的任意方法,哪怕是getClass()被調(diào)用,都會(huì)導(dǎo)致這個(gè)類中的靜態(tài)變量被初始化,如果這些靜態(tài)變量的初始化有實(shí)例賦值且實(shí)例構(gòu)造中會(huì)誘發(fā)各種耗時(shí)操作,也會(huì)對(duì)當(dāng)前線程造成很大影響。
代碼事例:
public class ServiceFacade {
public static A a = new A();
public static B b = new B();
public static A getA(){
return a;
}
...
}
3.反射
反射也是一個(gè)典型的耗時(shí)操作,包括類的反射實(shí)例化、field和方法的反射遍歷、注解的反射等等,其中,field和方法的反射遍歷、注解的反射最為耗時(shí),我們所有的很多框架中都有使用類似的反射,尤其是注解反射,如Retrofit、OrmLite、Butternife等等。當(dāng)然,他們的有些版本已經(jīng)將運(yùn)行時(shí)反射注解改成了編譯器aapt生成靜態(tài)代碼了。
以Retrofit為例,雖然網(wǎng)絡(luò)請(qǐng)求在線程中異步執(zhí)行,但是動(dòng)態(tài)代理的生成仍然是在當(dāng)前線程中通過(guò)反射實(shí)現(xiàn)的,所以使用此類框架時(shí)要注意其對(duì)性能的影響。
4.不必要的業(yè)務(wù)邏輯
這點(diǎn)不必多說(shuō),要讓APK快速啟動(dòng),怎容得這種勞民傷財(cái)?shù)氖虑榈R啟動(dòng)大業(yè),砍!
5.大量反復(fù)的重復(fù)查詢
萬(wàn)萬(wàn)不得已,有些UI線程中還有查詢數(shù)據(jù)庫(kù)的操作,或者一時(shí)改不成異步,但是也需要優(yōu)化查詢方式。
6.其它線程和進(jìn)程的資源搶占
BaseFragmentActivity的OnCreate()中bind了新的service進(jìn)程,導(dǎo)致大量的資源搶占,對(duì)啟動(dòng)性能造成了比較大的影響。
分析完了可能造成延緩的因素,再來(lái)說(shuō)一說(shuō)優(yōu)化的方案:
啟動(dòng)速度優(yōu)化是一個(gè)系統(tǒng)工程,涉及的面很廣,從業(yè)務(wù)邏輯到UI渲染,從線程調(diào)度到算法優(yōu)化,從性能分析到性能監(jiān)控。不僅要求開發(fā)者在開發(fā)的時(shí)候有敏感的性能意識(shí),還要求具有統(tǒng)顧全局的高度。用一句話概括,啟動(dòng)速度優(yōu)化更像是一門統(tǒng)籌學(xué)的實(shí)踐。
1.明確啟動(dòng)的優(yōu)化目標(biāo):讓用戶以最快的速度看到首屏,且不影響正常的業(yè)務(wù)邏輯。此外,以什么事件作為啟動(dòng)完成的標(biāo)志,也是需要明確的。
分析手段:先在啟動(dòng)的關(guān)鍵路徑上打點(diǎn),實(shí)踐表明,Log是最準(zhǔn)確的有效的打點(diǎn)方式(對(duì)性能影響最小,對(duì)線程時(shí)序影響最?。?,MathodTrace對(duì)線程執(zhí)行性能影響太大,且不容易在啟動(dòng)過(guò)程中使用。
關(guān)鍵點(diǎn):四大組件的生命周期,Application的onCreate(),Activiy的onCreate()、onStart()、onResume()、onWindowFocusChanged()
2.提前后臺(tái)加載
對(duì)于啟動(dòng)中需要的數(shù)據(jù)準(zhǔn)備、初始化等操作,可以利用多線程的形式,在后臺(tái)線程多提前加載,尤其是和IO相關(guān)的操作。
如:數(shù)據(jù)庫(kù)查詢、網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求、配置信息讀取、資源加載等;
等到主線程運(yùn)行到對(duì)應(yīng)節(jié)點(diǎn)時(shí),便可以直接“飯來(lái)張口、衣來(lái)伸手”了。
3.延遲加載+懶加載 (“懶加載”的原則是不能“懶”?。?/p>
a. 巧用單例
單例模式是懶加載天生的伴侶,哪里用到哪里最先加載初始化,類似的思路可以應(yīng)用在很多模塊的初始化上。但是也有需要注意的地方!
采用懶漢模式的單例,盡量不要在類中寫公有靜態(tài)方法。
b. 構(gòu)造方法中盡量少處理邏輯
單例模式的構(gòu)造方法中,盡量至保留必要的基礎(chǔ)邏輯,不要為了嫌麻煩把很多不必要的初始化操作放在構(gòu)造方法中,因?yàn)楹竺娌灰欢ㄒ玫健?/p>
c. 能懶加載的就懶加載,不要吝嗇判斷邏輯
遵循一個(gè)原則“用到再加載”。這一點(diǎn),就要求在對(duì)應(yīng)的邏輯上做很多類似單例的判斷,所以說(shuō),懶加載不能懶。
4.前后臺(tái)多線程多任務(wù)(統(tǒng)籌學(xué))
a. ?弄清依賴關(guān)系(集中方法)
逆推法:先總結(jié)確認(rèn)啟動(dòng)目標(biāo)的“最小集”,反向逆推構(gòu)建啟動(dòng)流程
刪減法:從頭至尾,以質(zhì)疑的眼光剔除不必要的邏輯(先錯(cuò)殺,殺不掉再救回)
b. ?統(tǒng)籌分配任務(wù)
規(guī)劃幾條關(guān)鍵路徑,弄清關(guān)鍵路徑之間的關(guān)鍵交點(diǎn)和節(jié)點(diǎn)
合理利用CPU資源,不宜開辟太多線程(同步異步邏輯不好處理,線程過(guò)多也降低效率)
根據(jù)打點(diǎn)摸清楚各個(gè)線程任務(wù)的開始結(jié)束點(diǎn),合理統(tǒng)籌
c. ?UI線程為關(guān)鍵路徑,此路徑上的絆腳石全部踢開
UI線程上,有些必須走的生命周期回調(diào)必須盡量提前,幾乎是越往前越好,因?yàn)橹挥羞@些回調(diào)都走完了,我們目標(biāo)的啟動(dòng)的回調(diào)才會(huì)調(diào)出來(lái)。
d. ?后臺(tái)多線程:
IO阻塞任務(wù)(如數(shù)據(jù)庫(kù)查詢、網(wǎng)絡(luò)請(qǐng)求等),這種以IO為主要資源占用的任務(wù),適合放在后臺(tái)線程處理,并且可以一開始就拋出去,以達(dá)到時(shí)間的最大化利用;
含有大量CPU計(jì)算工作的任務(wù),如果不是啟動(dòng)必須的,適合拋到首屏加載完成后執(zhí)行;
如果是啟動(dòng)必須的,也可以通過(guò)后臺(tái)線程來(lái)計(jì)算處理,理論上,多核CPU的性能可以在對(duì)應(yīng)線程數(shù)下發(fā)揮到最優(yōu),當(dāng)然,這個(gè)需要實(shí)驗(yàn)數(shù)據(jù)證明;
5.抓住關(guān)鍵節(jié)點(diǎn):onWindowFocusChanged()
onWindowFocusChanged可以粗略地作為Activity顯示的標(biāo)志節(jié)點(diǎn),此外還有一些節(jié)點(diǎn)也可以作為參考,如:IdleHandler等。
但是實(shí)驗(yàn)表明IdleHandler由于某些原因不太可靠,故以保險(xiǎn)起見(jiàn)棄用;
onWindowFocusChanged并不是只執(zhí)行一次,故需要加入“直走一次”的邏輯。
6.優(yōu)化視圖渲染
a. ?減少層級(jí)
b. ?布局文件優(yōu)化(LinearLayout\RelaitveLayout\FrameLayout)
c. ?巧用ViewStub
d. ?減少大資源加載,優(yōu)化大資源視圖實(shí)現(xiàn)
e. ?異步回調(diào)加載視圖
7.優(yōu)化數(shù)據(jù)庫(kù)查詢操作
a. ?能合并成一次的操作就合并成一次
b. ?至查詢條目數(shù)量的,就至調(diào)用queryCount, 只關(guān)心某個(gè)字段的,就只查詢某個(gè)字段(大多數(shù)情況還沒(méi)必要優(yōu)化到這么細(xì)致)
8.巧用內(nèi)存緩存
a. ?重復(fù)獲取的數(shù)據(jù)可以使用緩存(數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)等)
b. ?代價(jià)就是需要有額外的緩存數(shù)據(jù)同步機(jī)制,保證從緩存中獲取和從數(shù)據(jù)庫(kù)中獲取的結(jié)果一樣;
好了,以上就是這次整理的全部?jī)?nèi)容,歡迎大家補(bǔ)充,糾正,謝謝。