安卓性能優(yōu)化1——啟動(dòng)優(yōu)化

說到安卓性能優(yōu)化,這個(gè)話題實(shí)在是很廣动壤,之前在上上一家公司專門搞了一段時(shí)間的優(yōu)化锅风,發(fā)現(xiàn)APP的各個(gè)方面都得到性能上的提升酥诽,為此老板還給我獎(jiǎng)勵(lì)了1000塊錢。時(shí)間久了不去回顧皱埠,加上技術(shù)的日新月異肮帐,打算把自己積累的經(jīng)驗(yàn)重新整理回顧,不放在為知筆記了边器,太難找了训枢,暫且分幾個(gè)專題詳解:

1.啟動(dòng)的優(yōu)化
2.布局的優(yōu)化
3.內(nèi)存的優(yōu)化
4.電量的優(yōu)化
5.卡頓的優(yōu)化
6.流量的優(yōu)化

啟動(dòng)的優(yōu)化

啟動(dòng)緩慢導(dǎo)致的黑屏,白屏問題忘巧,大部分的答案都是做一個(gè)透明的主題恒界,或者是做一個(gè)Splash界面,這就是我在之前公司的臨時(shí)方案砚嘴。

APK啟動(dòng)原理

http://www.reibang.com/writer#/notebooks/11604270/notes/27710179/preview

APK的啟動(dòng)方式

1.冷啟動(dòng):后臺(tái)沒有該應(yīng)用的進(jìn)程十酣,這時(shí)系統(tǒng)會(huì)首先會(huì)創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用
由于冷啟動(dòng)過程中,系統(tǒng)和APP的許多工作都要重新開始际长,所以一般而言這種啟動(dòng)方式是最慢且最具有挑戰(zhàn)性的耸采。除了創(chuàng)建和初始化Application和MainActivity之外,冷啟動(dòng)還要加載主題樣式Theme工育,inflate布局虾宇,setContentView ,測(cè)量如绸、布局嘱朽、繪制以后顯示旭贬,我們才看到了屏幕的第一幀

也就是說當(dāng)用戶點(diǎn)擊你的app那一刻到系統(tǒng)調(diào)用Activity.onCreate()之間的這個(gè)時(shí)間段內(nèi),WindowManager會(huì)先加載app主題樣式中的windowBackground做為app的預(yù)覽元素搪泳,然后再真正去加載activity的layout布局稀轨。
為什么會(huì)出現(xiàn)黑屏白屏呢?
系統(tǒng)進(jìn)程在創(chuàng)建Application的過程中會(huì)產(chǎn)生一個(gè)BackgroudWindow森书,等到App完成了第一次繪制靶端,系統(tǒng)進(jìn)程才會(huì)用MainActivity的界面替換掉原來的BackgroudWindow
很顯然,如果你的application或activity啟動(dòng)的過程太慢凛膏,導(dǎo)致系統(tǒng)的BackgroundWindow沒有及時(shí)被替換杨名,就會(huì)出現(xiàn)啟動(dòng)時(shí)白屏或黑屏的情況(取決于你的主題是Dark還是Light)

冷啟動(dòng)優(yōu)化

1.主題替換

我們?cè)趕tyle中自定義一個(gè)樣式Lancher,在其中放一張背景圖片猖毫,或是廣告圖片之類的


1.  <style name="AppTheme.Launcher">  
2.  <item name="android:windowBackground">@drawable/bg</item>  
3.  </style>  

把這個(gè)樣式設(shè)置給啟動(dòng)的Activity

1.  <activity  
2.  android:name=".activity.SplashActivity"  
3.  android:screenOrientation="portrait"  
4.  android:theme="@style/AppTheme.Launcher"  
5.  >  

然后在Activity的onCreate方法台谍,把Activity設(shè)置回原來的主題

1.  @Override  
2.  protected void onCreate(Bundle savedInstanceState) {  
3.  //替換為原來的主題,在onCreate之前調(diào)用  
4.  setTheme(R.style.AppTheme);  
5.  super.onCreate(savedInstanceState);  
6.  }  

這樣在啟動(dòng)時(shí)就通過給用戶看一張圖片或是廣告來防止黑白屏的尷尬吁断。

還一種方式趁蕊,就是把windowBackground屬性設(shè)為null,這樣在啟動(dòng)時(shí)仔役,backgroundWindow的背景就會(huì)變成透明的掷伙,給人的感覺就是點(diǎn)了應(yīng)用圖標(biāo)以后,延遲了一會(huì)兒然后加載第一個(gè)activity的界面又兵。

1.  <style name="AppTheme.Launcher">  
2.  <item name="android:windowBackground">@null</item>  
3.  </style>

第二種方式可能會(huì)出現(xiàn)黑屏任柜,第一種的圖要選取好,不然也會(huì)有突兀感沛厨,所以很多公司都選擇就讓他白屏宙地,改變主題實(shí)際上是一種偽優(yōu)化,因?yàn)樗鼘?shí)質(zhì)上并沒有真正減少App啟動(dòng)的時(shí)間
另外還可以設(shè)置style

<style name="LaunchStyle" parent="AppTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
</style>
或者
<item name="android:windowDisablePreview">true</item>
這個(gè)就是直接甩鍋個(gè)系統(tǒng)

其他方法 就是進(jìn)入后直接動(dòng)畫逆皮,或者是MD模式的效果宅粥, GitHub 上的開源項(xiàng)目 saulmm/onboarding-examples-android

Application是程序的主入口

延遲初始化,后臺(tái)任務(wù)电谣,界面預(yù)加載
在Application的構(gòu)造器方法秽梅、attachBaseContext()、onCreate()方法中不要進(jìn)行耗時(shí)操作的初始化辰企,一些數(shù)據(jù)預(yù)取放在異步線程中风纠。

數(shù)據(jù)庫,IO操作牢贸,密集網(wǎng)絡(luò)請(qǐng)求不要放在Application的構(gòu)造方法中,能使用工作線程的盡量使用工作線程镐捧,不要在Application的onCreate中創(chuàng)建線程池潜索,因?yàn)槟菢訒?huì)有比較大的開銷臭增,可以考慮延后再創(chuàng)建。
第三方SDK如果主線程中沒有立即使用竹习,可以考慮延遲幾秒再初始化誊抛,總之一句話,盡早讓用戶看到應(yīng)用的界面整陌,其他操作都可以先讓路拗窃。

對(duì)于MainActivity,由于在獲取到第一幀前泌辫,需要對(duì)contentView進(jìn)行測(cè)量布局繪制操作随夸,盡量減少布局的層次,考慮StubView的延遲加載策略震放,當(dāng)然在onCreate宾毒、onStart、onResume方法中避免做耗時(shí)操作

  • MultiDex以及Tinker的初始化殿遂,最先執(zhí)行诈铛;關(guān)于MultiDex的優(yōu)化本文不再贅述,參考我之前Multidex的系列文章墨礁。
  • Application中主要做了各種三方組件的初始化幢竹;

項(xiàng)目中除聽云之外其余所有三方組件都搶占先機(jī),在Application主線程初始化恩静。這樣的初始化方式肯定是過重的:

  • 考慮異步初始化三方組件焕毫,不阻塞主線程;
  • 延遲部分三方組件的初始化蜕企;實(shí)際上我們粗粒度的把所有三方組件都放到異步任務(wù)里咬荷,可能會(huì)出現(xiàn)WorkThread中尚未初始化完畢但MainThread中已經(jīng)使用的錯(cuò)誤,因此這種情況建議延遲到使用前再去初始化轻掩;
  • 而如何開啟WorkThread同樣也有講究幸乒,這個(gè)話題在下文詳談。

項(xiàng)目修改:

  1. 將友盟唇牧、Bugly罕扎、聽云、GrowingIO丐重、BlockCanary等組件放在WorkThread中初始化腔召;
  2. 延遲地圖定位、ImageLoader扮惦、自有統(tǒng)計(jì)等組件的初始化:地圖及自有統(tǒng)計(jì)延遲4秒臀蛛,此時(shí)應(yīng)用已經(jīng)打開;而ImageLoader
    因?yàn)檎{(diào)用關(guān)系不能異步以及過久延遲,初始化從Application延遲到SplashActivity浊仆;而EventBus因?yàn)樵貯ctivity中使用所以必須在Application中初始化

2.溫啟動(dòng):臺(tái)已有該應(yīng)用的進(jìn)程客峭,但是啟動(dòng)的入口Activity被干掉了,比如按了back鍵抡柿,應(yīng)用雖然退出了舔琅,但是該應(yīng)用的進(jìn)程是依然會(huì)保留在后臺(tái)
3.熱啟動(dòng):后臺(tái)已有該應(yīng)用的進(jìn)程,比如按下home鍵洲劣,這種在已有進(jìn)程的情況下备蚓,這種啟動(dòng)會(huì)從已有的進(jìn)程中來啟動(dòng)應(yīng)用

應(yīng)用的啟動(dòng)時(shí)間統(tǒng)計(jì)

在現(xiàn)在的公司最近還在搞啟動(dòng)優(yōu)化,提供2種方式

1.查看啟動(dòng)時(shí)間adb 命令
adb shell am start -W [PackageName]/[PackageName.XX.XXXActivity]

這個(gè)PackageName 需要你到你自己項(xiàng)目的清單文件去自己找囱稽,輸入adb命令后郊尝,程序會(huì)等待你啟動(dòng)然后在統(tǒng)計(jì)這個(gè)時(shí)間,


image.png

ThisTime:最后一個(gè)啟動(dòng)的Activity的啟動(dòng)耗時(shí)粗悯; ThisTime:一般和TotalTime時(shí)間一樣虚循,我們的是中間開了一個(gè)
TotalTime:自己的所有Activity的啟動(dòng)耗時(shí);包括創(chuàng)建進(jìn)程+Application初始化+Activity初始化到界面顯示
WaitTime: ActivityManagerService啟動(dòng)App的Activity時(shí)的總時(shí)間(包括當(dāng)前Activity的onPause()和自己Activity的啟動(dòng))一般比TotalTime大點(diǎn)样傍,包括系統(tǒng)影響的耗時(shí)

2.使用Android Studio 的日志横缔,在過濾框輸入display

然后清空日志,然后啟動(dòng)如下:


image.png

Application開始到首頁顯示出來

Application的構(gòu)造器方法——>attachBaseContext()——>onCreate()——>Activity的構(gòu)造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測(cè)量衫哥、布局茎刚、繪制顯示在界面上

上面這些階段全部都是在主線程中執(zhí)行的,任何不經(jīng)意的操作都可能拖慢應(yīng)用的啟動(dòng)速度撤逢。所以我們不應(yīng)在Application以及Activity的生命周期回調(diào)中做任何費(fèi)時(shí)操作膛锭,具體指標(biāo)大概是你在onCreate,onResume蚊荣,onStart等回調(diào)中所花費(fèi)的總時(shí)間最好不要超過400ms初狰,否則用戶在桌面點(diǎn)擊你的應(yīng)用圖標(biāo)后,將感覺到明顯的卡頓

針對(duì)上面的需求互例,一般處理是將任務(wù)分優(yōu)先級(jí)啟動(dòng)奢入,應(yīng)用啟動(dòng)開始加載 ;首頁渲染后加載媳叨;渲染后延遲加載
具體延遲多久 在性能好的手機(jī)上面啟動(dòng)非承裙猓快,很短的延遲就行了,但是在低端手機(jī)上缺很慢,還要為了兼容久手機(jī)覆旱,一般延長(zhǎng)很長(zhǎng)的時(shí)間,

  第一種寫法:直接PostDelay 300ms.
  myHandler.postDelayed(mLoadingRunnable, DEALY_TIME);
  第二種寫法:優(yōu)化的DelayLoad
  getWindow().getDecorView().post(new Runnable() {
    @Override
   public void run() {
        myHandler.post(mLoadingRunnable);
   }
  });

第二種捉片,在窗口完成以后進(jìn)行加載,這里面的run方法是在onResume之后運(yùn)行的具體參考這個(gè):http://www.androidperformance.com/2015/11/18/Android-app-lunch-optimize-delay-load.html

啟動(dòng)優(yōu)化思路

1、UI渲染優(yōu)化界睁,去除重復(fù)繪制觉增,減少UI重復(fù)繪制時(shí)間兵拢,打開設(shè)置中的GPU過度繪制開關(guān)翻斟,各界面過度繪制不應(yīng)超過2.5x;也就是打開此調(diào)試開關(guān)后说铃,界面整體呈現(xiàn)淺色访惜,特別復(fù)雜的界面,紅色區(qū)域也不應(yīng)該超過全屏幕的四分之一腻扇;
2债热、根據(jù)優(yōu)先級(jí)的劃分,KoMobileApplication的一些初始化工作能否將任務(wù)優(yōu)先級(jí)劃分成3,在首頁渲染完成后進(jìn)行加載幼苛,比如:PaySDKManager窒篱。
3、主線程中的所有SharedPreference能否在非UI線程中進(jìn)行舶沿,SharedPreferences的apply函數(shù)需要注意墙杯,因?yàn)镃ommit函數(shù)會(huì)阻塞IO,這個(gè)函數(shù)雖然執(zhí)行很快括荡,但是系統(tǒng)會(huì)有另外一個(gè)線程來負(fù)責(zé)寫操作高镐,當(dāng)apply頻率高的時(shí)候,該線程就會(huì)比較占用CPU資源畸冲。類似的還有統(tǒng)計(jì)埋點(diǎn)等嫉髓,在主線程埋點(diǎn)但異步線程提交,頻率高的情況也會(huì)出現(xiàn)這樣的問題邑闲。
4算行、檢查BaseActivity,不恰當(dāng)?shù)牟僮鲿?huì)影響所有子Activity的啟動(dòng)。
5苫耸、對(duì)于首次啟動(dòng)的黑屏問題州邢,對(duì)于“黑屏”是否可以設(shè)計(jì)一個(gè).9圖片替換掉,間接減少用戶等待時(shí)間鲸阔。
6偷霉、對(duì)于網(wǎng)絡(luò)錯(cuò)誤界面,友好提示界面褐筛,使用ViewStub的方式类少,減少UI一次性繪制的壓力。
7渔扎、任務(wù)優(yōu)先級(jí)為2硫狞,3的,通過下面這種方式進(jìn)行懶加載的方式

getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
myHandler.post(mLoadingRunnable);
}
});
8、Multidex的使用残吩,也是拖慢啟動(dòng)速度的元兇财忽,必須要做優(yōu)化。后面有空專門寫一篇Multidex

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泣侮,一起剝皮案震驚了整個(gè)濱河市即彪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌活尊,老刑警劉巖隶校,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蛹锰,居然都是意外死亡深胳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門铜犬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舞终,“玉大人,你說我怎么就攤上這事癣猾×踩埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵煎谍,是天一觀的道長(zhǎng)攘蔽。 經(jīng)常有香客問我,道長(zhǎng)呐粘,這世上最難降的妖魔是什么满俗? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮作岖,結(jié)果婚禮上唆垃,老公的妹妹穿的比我還像新娘。我一直安慰自己痘儡,他們只是感情好辕万,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沉删,像睡著了一般渐尿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矾瑰,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天砖茸,我揣著相機(jī)與錄音,去河邊找鬼殴穴。 笑死凉夯,一個(gè)胖子當(dāng)著我的面吹牛货葬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播劲够,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼震桶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了征绎?” 一聲冷哼從身側(cè)響起蹲姐,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炒瘸,沒想到半個(gè)月后淤堵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顷扩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慰毅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隘截。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖汹胃,靈堂內(nèi)的尸體忽然破棺而出婶芭,到底是詐尸還是另有隱情,我是刑警寧澤着饥,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布犀农,位于F島的核電站,受9級(jí)特大地震影響宰掉,放射性物質(zhì)發(fā)生泄漏呵哨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一轨奄、第九天 我趴在偏房一處隱蔽的房頂上張望孟害。 院中可真熱鬧,春花似錦挪拟、人聲如沸挨务。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谎柄。三九已至,卻和暖如春惯雳,著一層夾襖步出監(jiān)牢的瞬間朝巫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工吨凑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捍歪,地道東北人户辱。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像糙臼,于是被迫代替她去往敵國(guó)和親庐镐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,178評(píng)論 25 707
  • 請(qǐng)保持淡定变逃,分析代碼必逆,記住:性能很重要揽乱。 啟動(dòng)時(shí)間優(yōu)化 毫無疑問名眉,應(yīng)用的啟動(dòng)速度越快越好。 本文可以幫助你優(yōu)化應(yīng)用...
    Mupceet閱讀 11,402評(píng)論 5 19
  • 轉(zhuǎn)載自一觸即發(fā) App啟動(dòng)優(yōu)化最佳實(shí)踐 一觸即發(fā) App啟動(dòng)優(yōu)化最佳實(shí)踐 文中的很多圖都是Google性能優(yōu)化指南...
    CP9閱讀 601評(píng)論 0 3
  • 圖/網(wǎng)絡(luò) 這幾天微博朋友圈就被刷屏了。吃瓜群眾都在看林丹出軌的消息撒犀,這個(gè)話題已經(jīng)登上了微博熱搜福压。 猶記得前不久還看...
    夏至星輝閱讀 202評(píng)論 0 1
  • 我站在高高的后山崗上, 看霓虹在眼前閃著縹緲的光或舞, 這城市的聒噪荆姆, 纏綿在凄冷的夜里, 竟沒有一點(diǎn)聲響映凳。 是不是這...
    俗人阿久閱讀 209評(píng)論 0 1