自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android性能優(yōu)化之啟動加速35%

移動開發(fā) Android
隨著項目版本的迭代,App的性能問題會逐漸暴露出來,而好的用戶體驗與性能表現(xiàn)緊密相關(guān),從本篇文章開始,我將開啟一個Android應(yīng)用性能優(yōu)化的專題,從理論到實戰(zhàn),從入門到深挖,手把手將性能優(yōu)化實踐到項目中,歡迎持續(xù)關(guān)注!

一、前言

隨著項目版本的迭代,App的性能問題會逐漸暴露出來,而好的用戶體驗與性能表現(xiàn)緊密相關(guān),從本篇文章開始,我將開啟一個Android應(yīng)用性能優(yōu)化的專題,從理論到實戰(zhàn),從入門到深挖,手把手將性能優(yōu)化實踐到項目中,歡迎持續(xù)關(guān)注!

那么第一篇文章我就從應(yīng)用的啟動優(yōu)化開始,根據(jù)實際案例,打造閃電般的App啟動速度。

二、初識啟動加速

來看一下Google官方文檔《Launch-Time Performance》(https://ldeveloper.android.com/topic/performance/launch-time.html)對應(yīng)用啟動優(yōu)化的概述;

應(yīng)用的啟動分為冷啟動、熱啟動、溫啟動,而啟動最慢、挑戰(zhàn)最大的就是冷啟動:系統(tǒng)和App本身都有更多的工作要從頭開始!

應(yīng)用在冷啟動之前,要執(zhí)行三個任務(wù):

  • 加載啟動App;
  • App啟動之后立即展示出一個空白的Window;
  • 創(chuàng)建App的進(jìn)程;

而這三個任務(wù)執(zhí)行完畢之后會馬上執(zhí)行以下任務(wù):

  • 創(chuàng)建App對象;
  • 啟動Main Thread;
  • 創(chuàng)建啟動的Activity對象;
  • 加載View;
  • 布置屏幕;
  • 進(jìn)行第一次繪制;

而一旦App進(jìn)程完成了第一次繪制,系統(tǒng)進(jìn)程就會用Main Activity替換已經(jīng)展示的Background Window,此時用戶就可以使用App了。

Android性能優(yōu)化之啟動加速35%

作為普通應(yīng)用,App進(jìn)程的創(chuàng)建等環(huán)節(jié)我們是無法主動控制的,可以優(yōu)化的也就是Application、Activity創(chuàng)建以及回調(diào)等過程。

同樣,Google也給出了啟動加速的方向:

  • 利用提前展示出來的Window,快速展示出來一個界面,給用戶快速反饋的體驗;
  • 避免在啟動時做密集沉重的初始化(Heavy app initialization);
  • 定位問題:避免I/O操作、反序列化、網(wǎng)絡(luò)操作、布局嵌套等。

備注:方向1屬于治標(biāo)不治本,只是表面上快;方向2、3可以真實的加快啟動速度。

接下來我們就在項目中實際應(yīng)用。

三、啟動加速之主題切換

按照官方文檔的說明:使用Activity的windowBackground主題屬性來為啟動的Activity提供一個簡單的drawable。

Layout XML file:

Android性能優(yōu)化之啟動加速35%

Manifest file:

Android性能優(yōu)化之啟動加速35%

Android性能優(yōu)化之啟動加速35%

這樣在啟動的時候,會先展示一個界面,這個界面就是Manifest中設(shè)置的Style,等Activity加載完畢后,再去加載Activity的界面,而在Activity的界面中,我們將主題重新設(shè)置為正常的主題,從而產(chǎn)生一種快的感覺。不過如上文總結(jié)這種方式其實并沒有真正的加速啟動過程,而是通過交互體驗來優(yōu)化了展示的效果。

備注:截圖同樣來自官方文檔《Launch-Time Performance》。

四、啟動加速之Avoid Heavy App Initialization

通過代碼分析我們可以得到App啟動的業(yè)務(wù)工作流程圖:

Android性能優(yōu)化之啟動加速35%

這一章節(jié)我們重點關(guān)注初始化的部分:在Application以及首屏Activity中我們主要做了:

  • MultiDex以及Tinker的初始化,最先執(zhí)行;
  • Application中主要做了各種三方組件的初始化;

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

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

項目修改:

  • 將友盟、Bugly、聽云、GrowingIO、BlockCanary等組件放在WorkThread中初始化;
  • 延遲地圖定位、ImageLoader、自有統(tǒng)計等組件的初始化:地圖及自有統(tǒng)計延遲4秒,此時應(yīng)用已經(jīng)打開;而ImageLoader
  • 因為調(diào)用關(guān)系不能異步以及過久延遲,初始化從Application延遲到SplashActivity;而EventBus因為再Activity中使用所以必須在Application中初始化。

Android性能優(yōu)化之啟動加速35%

注意:閃屏頁的2秒停留可以利用,把耗時操作延遲到這個時間間隔里。

五、啟動加速之Diagnosing The Problem

本節(jié)我們實際定位耗時的操作,在開發(fā)階段我們一般使用BlockCanary或者ANRWatchDog找耗時操作,簡單明了,但是無法得到每一個方法的執(zhí)行時間以及更詳細(xì)的對比信息。我們可以通過Method Tracing或者DDMS來獲得更全面詳細(xì)的信息。

啟動應(yīng)用,點擊 Start Method Tracing,應(yīng)用啟動后再次點擊,會自動打開剛才操作所記錄下的.trace文件,建議使用DDMS來查看,功能更加方便全面。

Android性能優(yōu)化之啟動加速35%

Android性能優(yōu)化之啟動加速35%

左側(cè)為發(fā)生的具體線程,右側(cè)為發(fā)生的時間軸,下面是發(fā)生的具體方法信息。注意兩列:Real Time/Call(實際發(fā)生時間),Calls+RecurCalls/Total(發(fā)生次數(shù));

上圖我們可以得到以下信息:

  • 可以直觀看到MainThread的時間軸很長,說明大多數(shù)任務(wù)都是在MainThread中執(zhí)行;
  • 通過Real Time/Call 降序排列可以看到程序中的部分代碼確實非常耗時;
  • 在下一頁可以看出來部分三方SDK也比較耗時;

即便是耗時操作,但是只要正確發(fā)生在WorkThread就沒問題。因此我們需要確認(rèn)這些方法執(zhí)行的線程以及發(fā)生的時機(jī)。這些操作如果發(fā)生在主線程,可能不構(gòu)成ANR的發(fā)生條件,但是卡頓是再算難免的!結(jié)合上章節(jié)圖App冷啟動業(yè)務(wù)工作流程圖中業(yè)務(wù)操作以及分析圖,再次查看代碼我們可以看到:部分耗時操作例如IO讀取等確實發(fā)生在主線程。事實上在traceview里點擊執(zhí)行函數(shù)的名稱不僅可以跟蹤到父類及子類的方法耗時,也可以在方法執(zhí)行時間軸中看到具體在哪個線程以及耗時的界面閃動。

分析到部分耗時操作發(fā)生在主線程,那我們把耗時操作都改到子線程是不是就萬事大吉了?非也!!

卡頓不能都靠異步來解決,錯誤的使用工程線程不僅不能改善卡頓,反而可能加劇卡頓。是否需要開啟工作線程需要根據(jù)具體的性能瓶頸根源具體分析,對癥下藥,不可一概而論;

而如何開啟線程同樣也有學(xué)問:Thread、ThreadPoolExecutor、AsyncTask、HandlerThread、IntentService等都各有利弊;例如通常情況下ThreadPoolExecutor比Thread更加高效、優(yōu)勢明顯,但是特定場景下單個時間點的表現(xiàn)Thread會比ThreadPoolExecutor好:同樣的創(chuàng)建對象,ThreadPoolExecutor的開銷明顯比Thread大;

正確的開啟線程也不能包治百病,例如執(zhí)行網(wǎng)絡(luò)請求會創(chuàng)建線程池,而在Application中正確的創(chuàng)建線程池勢必也會降低啟動速度;因此延遲操作也必不可少。

通過對traceview的詳細(xì)跟蹤以及代碼的詳細(xì)比對,我發(fā)現(xiàn)卡頓發(fā)生在:

  • 部分?jǐn)?shù)據(jù)庫及IO的操作發(fā)生在首屏Activity主線程;
  • Application中創(chuàng)建了線程池;
  • 首屏Activity網(wǎng)絡(luò)請求密集;
  • 工作線程使用未設(shè)置優(yōu)先級;
  • 信息未緩存,重復(fù)獲取同樣信息;
  • 流程問題:例如閃屏圖每次下載,當(dāng)次使用;

以及其它細(xì)節(jié)問題:

  • 執(zhí)行無用老代碼;
  • 執(zhí)行開發(fā)階段使用的代碼;
  • 執(zhí)行重復(fù)邏輯;
  • 調(diào)用三方SDK里或者Demo里的多余代碼;

項目修改:

1. 數(shù)據(jù)庫及IO操作都移到工作線程,并且設(shè)置線程優(yōu)先級為THREAD_PRIORITY_BACKGROUND,這樣工作線程最多能獲取到10%的時間片,優(yōu)先保證主線程執(zhí)行。

2. 流程梳理,延后執(zhí)行;

實際上,這一步對項目啟動加速最有效果。通過流程梳理發(fā)現(xiàn)部分流程調(diào)用時機(jī)偏早、失誤等,例如:

更新等操作無需在首屏尚未展示就調(diào)用,造成資源競爭;

調(diào)用了IOS為了規(guī)避審核而做的開關(guān),造成網(wǎng)絡(luò)請求密集;

自有統(tǒng)計在Application的調(diào)用里創(chuàng)建數(shù)量固定為5的線程池,造成資源競爭,在上圖traceview功能說明圖中最后一行可以看到編號12執(zhí)行5次,耗時排名前列;此處線程池的創(chuàng)建是必要但可以延后的。

修改廣告閃屏邏輯為下次生效。

3.其它優(yōu)化;

  • 去掉無用但被執(zhí)行的老代碼;
  • 去掉開發(fā)階段使用但線上被執(zhí)行的代碼;
  • 去掉重復(fù)邏輯執(zhí)行代碼;
  • 去掉調(diào)用三方SDK里或者Demo里的多余代碼;
  • 信息緩存,常用信息只在第一次獲取,之后從緩存中取;
  • 項目是多進(jìn)程架構(gòu),只在主進(jìn)程執(zhí)行Application的onCreate();

Android性能優(yōu)化之啟動加速35%

通過以上三步及三方組件的優(yōu)化:Application以及首屏Activity回調(diào)期間主線程就沒有耗時、爭搶資源等情況了。此外還涉及布局優(yōu)化、內(nèi)存優(yōu)化等部分技術(shù),因?qū)τ趹?yīng)用冷啟動一般不是瓶頸點,這里不展開詳談,可根據(jù)實際項目實際處理。

六、對比效果:

通過ADB命令統(tǒng)計應(yīng)用的啟動時間:adb shell am start -W 首屏Activity。

同等條件下使用MX3及Nexus6P,啟動5次,比較優(yōu)化前與優(yōu)化后的啟動時間;

優(yōu)化前:

MX3

Android性能優(yōu)化之啟動加速35%

Nexus6P

Android性能優(yōu)化之啟動加速35%

優(yōu)化后:

MX3

Android性能優(yōu)化之啟動加速35%

Nexus6P

Android性能優(yōu)化之啟動加速35%

對比:

MX3提升35%

Android性能優(yōu)化之啟動加速35%

Nexus6P提升39%

Android性能優(yōu)化之啟動加速35%

命令含義:

  • ThisTime:最后一個啟動的Activity的啟動耗時;
  • TotalTime:自己的所有Activity的啟動耗時;
  • WaitTime: ActivityManagerService啟動App的Activity時的總時間(包括當(dāng)前Activity的onPause()和自己Activity的啟動)。

七、問題:

1、還可以繼續(xù)優(yōu)化的方向?

  • 項目里使用Retrofit網(wǎng)絡(luò)請求庫,F(xiàn)astConverterFactory做Json解析器,TraceView中看到FastConverterFactory在創(chuàng)建過程中也比較耗時,考慮將其換為GsonConverterFactory。但是因為類的繼承關(guān)系短時間內(nèi)無法直接替換,作為優(yōu)化點暫時遺留;
  • 可以考慮根據(jù)實際情況將啟動時部分接口合并為一,減少網(wǎng)絡(luò)請求次數(shù),降低頻率;
  • 相同功能的組件只保留一個,例如:友盟、GrowingIO、自有統(tǒng)計等功能重復(fù);
  • 使用ReDex進(jìn)行優(yōu)化;實驗Redex發(fā)現(xiàn)Apk體積確實是小了一點,但是啟動速度沒有變化,或許需要繼續(xù)研究。

2、異步、延遲初始化及操作的依據(jù)?

注意一點:并不是每一個組件的初始化以及操作都可以異步或延遲;是否可以取決組件的調(diào)用關(guān)系以及自己項目具體業(yè)務(wù)的需要。保證一個準(zhǔn)則:可以異步的都異步,不可以異步的盡量延遲。讓應(yīng)用先啟動,再操作。

3、通用應(yīng)用啟動加速套路?

  • 利用主題快速顯示界面;
  • 異步初始化組件;
  • 梳理業(yè)務(wù)邏輯,延遲初始化組件、操作;
  • 正確使用線程;
  • 去掉無用代碼、重復(fù)邏輯等。

4、其它

  • 將啟動速度加快了35%不代表之前的代碼都是問題,從業(yè)務(wù)角度上將,代碼并沒有錯誤,實現(xiàn)了業(yè)務(wù)需求。但是在啟動時這個注重速度的階段,忽略的細(xì)節(jié)就會導(dǎo)致性能的瓶頸。
  • 開發(fā)過程中,對核心模塊與應(yīng)用階段如啟動時,使用TraceView進(jìn)行分析,盡早發(fā)現(xiàn)瓶頸。

 

責(zé)任編輯:未麗燕 來源: 安卓巴士
相關(guān)推薦

2019-12-13 10:25:08

Android性能優(yōu)化啟動優(yōu)化

2021-07-29 14:20:34

網(wǎng)絡(luò)優(yōu)化移動互聯(lián)網(wǎng)數(shù)據(jù)存儲

2013-02-20 14:32:37

Android開發(fā)性能

2021-07-12 23:43:46

AppAndroid優(yōu)化

2013-09-17 10:32:08

Android性能優(yōu)化數(shù)據(jù)庫

2015-09-16 15:48:55

Android性能優(yōu)化電量

2015-09-16 14:37:50

Android性能優(yōu)化運算

2015-09-16 13:54:30

Android性能優(yōu)化渲染

2022-03-29 13:27:22

Android優(yōu)化APP

2015-11-05 09:02:05

Java代碼性能優(yōu)化

2011-03-11 15:53:00

LAMP優(yōu)化

2017-01-15 15:13:37

Android性能優(yōu)化優(yōu)化點

2017-12-23 14:38:41

Android編程開發(fā)優(yōu)化

2022-02-16 14:10:51

服務(wù)器性能優(yōu)化Linux

2021-11-29 11:13:45

服務(wù)器網(wǎng)絡(luò)性能

2021-07-27 20:51:02

AndroidDNS網(wǎng)絡(luò)

2009-06-30 11:23:02

性能優(yōu)化

2018-01-09 16:56:32

數(shù)據(jù)庫OracleSQL優(yōu)化

2022-04-28 15:07:41

抖音內(nèi)存泄漏Android

2025-01-20 09:09:59

點贊
收藏

51CTO技術(shù)棧公眾號