Android性能優(yōu)化

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

冷啟動(dòng)

冷啟動(dòng)指的是應(yīng)用程序從頭開(kāi)始:系統(tǒng)的進(jìn)程沒(méi)有麸折,直到此開(kāi)始,創(chuàng)建了應(yīng)用程序的進(jìn)程粘昨。 在應(yīng)用程序自設(shè)備啟動(dòng)以來(lái)第一次啟動(dòng)或系統(tǒng)殺死應(yīng)用程序等情況下會(huì)發(fā)生冷啟動(dòng)垢啼。

Click Event ->IPC ->Process.start ->ActivityThread ->bindApplication ->LifeCycle ->ViewRootImpl

熱啟動(dòng)

應(yīng)用駐留在內(nèi)存中,會(huì)從后臺(tái)放回到前臺(tái)展示张肾,避免重復(fù)對(duì)象初始化芭析、UI布局和渲染。

后臺(tái)->前臺(tái)

溫啟動(dòng)

用戶退出了應(yīng)用吞瞪,但隨后又重啟馁启,這時(shí)候會(huì)進(jìn)程和Activity生命周期都會(huì)重走。

LifeCycle

可使用一下工具獲取啟動(dòng)時(shí)間:

  • TraceView
    wall time:方法執(zhí)行總時(shí)間
    cpu time:cpu在這個(gè)方法上使用的時(shí)間

  • adb命令:adb shell am start -W –n <packageName>/<activityName>
    加上 -s 就是殺掉重啟應(yīng)用
    如果只關(guān)心某個(gè)應(yīng)用自身啟動(dòng)耗時(shí)尸饺,參考TotalTime进统;
    如果關(guān)心系統(tǒng)啟動(dòng)應(yīng)用耗時(shí),參考WaitTime浪听;
    如果關(guān)心應(yīng)用有界面Activity啟動(dòng)耗時(shí)螟碎,參考ThisTime。

優(yōu)化小技巧:

  • Theme主題切換:感覺(jué)上快了迹栓。在app啟動(dòng)時(shí)候使用一個(gè)帶logo的主題掉分,MainActivity起來(lái)后,在super.onCreate(savedInstanceState)前把主題setTheme回來(lái)克伊。
  • 異步優(yōu)化:使用封裝的線程池酥郭,子線程(每個(gè)子線程只干一件事)分擔(dān)主線程任務(wù),并行減少時(shí)間愿吹。
    注意事項(xiàng):
    1.不符合異步要求不从,要改;
    2.需要在某階段完成犁跪,使用CountDownLatch保證線程同步椿息;
    3.區(qū)分CPU密集型和IO密集型任務(wù)。CPU密集型則不能創(chuàng)建過(guò)多線程坷衍,會(huì)消耗CPU運(yùn)算資源寝优,而IO密集型則可以創(chuàng)建多個(gè)線程去操作。
  • 啟動(dòng)器優(yōu)化
    1.區(qū)分主線程枫耳、子線程運(yùn)用乏矾,非必主線程運(yùn)行的都可以移植到子線程去做;
    2.執(zhí)行時(shí)機(jī)、順序依賴钻心;
    3.使用IdleHandler優(yōu)化凄硼;主要用在我們希望能夠在當(dāng)前線程消息隊(duì)列空閑時(shí)做些事情。譬如 UI 線程在顯示完成后扔役,如果線程空閑我們就可以提前準(zhǔn)備其他內(nèi)容的情況下帆喇,不過(guò)最好不要做耗時(shí)操作。

內(nèi)存優(yōu)化

工具:

  • Memory Profiler
  • Memory Analyzer

內(nèi)存抖動(dòng)觀察:內(nèi)存使用圖會(huì)程鋸齒狀亿胸,忽高忽低。

  • 使用Memory Profiler初步排查
  • 找循環(huán)或者頻繁調(diào)用的地方

內(nèi)存泄漏:可用內(nèi)存減少预皇,頻繁GC侈玄。
內(nèi)存溢出:OOM、程序異常退出吟温。

獲取Bitmap占用內(nèi)存:

  • getByteCount
  • 一像素占用內(nèi)存

圖片優(yōu)化:圖片加載要控制寬高序仙,壓縮編碼。

可使用hook方法去監(jiān)聽(tīng)內(nèi)存實(shí)時(shí)使用情況:

  • ARTHook:無(wú)侵入性鲁豪、通用性強(qiáng)潘悼、兼容問(wèn)題大,開(kāi)源方案不能帶到線上環(huán)境爬橡。
  • Epic:是一個(gè)虛擬機(jī)層面治唤、以Java Method為粒度的運(yùn)行時(shí)Hook框架。

優(yōu)化方案:

  • 開(kāi)啟LargeHeap屬性糙申,有機(jī)會(huì)獲取2倍的系統(tǒng)分配內(nèi)存宾添。注意:作為程序員的我們應(yīng)該努力減少內(nèi)存的使用,盡量想回收和復(fù)用的方法柜裸,而不是想方設(shè)法增大內(nèi)存缕陕。當(dāng)內(nèi)存很大的時(shí)候,每次gc的時(shí)間也會(huì)長(zhǎng)一些疙挺,性能會(huì)下降的扛邑。
  • onTrimMemory,這個(gè)方法執(zhí)行铐然,證明系統(tǒng)內(nèi)存不足蔬崩,必須要做資源釋放愿伴,以保存app為上策驹溃,避免被系統(tǒng)殺死。
  • 使用SparseArray等就轧。
  • 謹(jǐn)慎使用SharedPreference险掀,讀取的時(shí)候會(huì)加載全部數(shù)據(jù)到內(nèi)存中沪袭,性能差。
  • 謹(jǐn)慎使用外部庫(kù),要清楚外部庫(kù)寫(xiě)法冈绊,是否本身就存在內(nèi)存泄漏等問(wèn)題侠鳄。

布局優(yōu)化

一個(gè)像數(shù)最好只被繪制一次∷佬可在開(kāi)發(fā)者選項(xiàng)里面伟恶,開(kāi)啟調(diào)試GPU過(guò)度繪制,可以看到頁(yè)面繪制情況毅该。

優(yōu)化方法:

  • 16ms內(nèi)刷新不卡頓博秫,刷新頻率60Hz,在這個(gè)范圍內(nèi)可認(rèn)為是流暢不卡頓的眶掌。
  • InflaterLayout.Factory:當(dāng)我們使用自定義view時(shí)挡育,需要在xml中使用完整類(lèi)名,系統(tǒng)實(shí)際就是根據(jù)完整類(lèi)名進(jìn)行反射構(gòu)建朴爬。我們可以自己new出view避免系統(tǒng)反射調(diào)用即寒,提高效率。
  • AsyncLayoutInflater:WorkThread加載布局召噩,回調(diào)主線程母赵。加載布局xml文件是一個(gè)IO操作過(guò)程。
  • X2C:框架具滴,APT編譯器翻譯XML為Java代碼凹嘲,解決IO讀取、反射使用等問(wèn)題抵蚊。但不支持merge標(biāo)簽和使用系統(tǒng)Style施绎。
  • 減少View樹(shù)層級(jí),盡量使用ConstraintLayout贞绳、不嵌套使用RelativeLayout谷醉、不在嵌套LinearLayout中使用weight。
  • 使用merge標(biāo)簽冈闭,共用父布局俱尼,但只能繪制在根view中。
  • 使用Viewstub萎攒,高效占位符遇八,延遲初始化。
  • 去掉多余背景色耍休,減少?gòu)?fù)雜shape使用刃永。
  • 自定義view重疊時(shí)候要使用clipRect指定繪制區(qū)域,onDraw中避免創(chuàng)建大對(duì)象羊精、耗時(shí)操作斯够。

卡頓優(yōu)化

工具:CPU Profilder、Systrace、StrictMode读规。

自動(dòng)化卡頓檢測(cè)方案原理:

  • 消息處理機(jī)制抓督,一個(gè)線程只有一個(gè)Looper。
  • mLogging對(duì)象在每個(gè)message處理前后被調(diào)用束亏。
  • 主線程發(fā)生卡頓铃在,是在dispatchMessage執(zhí)行耗時(shí)操作。

具體檢測(cè)卡頓做法:

  • Looper在其loop方法中的死循環(huán)中有個(gè)mLogging對(duì)象碍遍,在執(zhí)行的時(shí)候打印了一個(gè)Dispatching to日志定铜,執(zhí)行完成的時(shí)候有打印了一個(gè)Finished to日志。
  • 可以自定義Printer對(duì)象怕敬,讓Handler的日志都通過(guò)我們自定義的Printer進(jìn)行打印宿稀,然后收集日志信息,匹配Dispatching to和Finished to字段赖捌,如果在設(shè)定的某個(gè)時(shí)間內(nèi)只有Dispatching to字段而沒(méi)有Finished to字段,那么就說(shuō)明發(fā)生了卡頓矮烹。發(fā)生卡頓后我們就收集此時(shí)的調(diào)用棧信息越庇。

ANR介紹

會(huì)發(fā)生ANR的情況:

  • 按鍵5s。
  • 廣播奉狈,前臺(tái)10s卤唉,后臺(tái)60s。
  • 服務(wù)仁期,前臺(tái)20s桑驱,后臺(tái)200s。

檢測(cè)方案:

  • Android Performance Monitor(BlockCanary):監(jiān)控msg跛蛋,如果應(yīng)用發(fā)生卡頓熬的,一定是在dispatchMessage中執(zhí)行了耗時(shí)操作。通過(guò)給主線程的Looper設(shè)置一個(gè)Printer赊级,打點(diǎn)統(tǒng)計(jì)dispatchMessage方法執(zhí)行的時(shí)間押框,如果超出閥值,表示發(fā)生卡頓理逊,則dump出各種信息橡伞,提供開(kāi)發(fā)者分析性能瓶頸。
  • ANR-WatchDog庫(kù)原理:開(kāi)始線程->post改變數(shù)值->sleep一段時(shí)間->檢測(cè)數(shù)值是否被修改->沒(méi)有修改晋被,證明發(fā)生ANR兑徘。
  • Lancet:輕量級(jí)AOP庫(kù),可使用它進(jìn)行方法執(zhí)行時(shí)間檢測(cè)羡洛。

線程優(yōu)化

線程使用情況:

  • 任意時(shí)刻挂脑,只有一個(gè)線程占用CPU,處于運(yùn)行狀態(tài)。
  • 多線程并發(fā):輪流獲取CPU使用權(quán)最域。
  • JVM負(fù)責(zé)線程調(diào)度:按照特定機(jī)制分配CPU使用權(quán)谴分。

Android線程調(diào)度:

  • 設(shè)置線程nice值:在process中定義,值越小镀脂,優(yōu)先級(jí)越高牺蹄,默認(rèn)是0,在Android中薄翅,nice的取值范圍為-20~19沙兰。
  • cgroup,更嚴(yán)格的群組調(diào)度策略翘魄,保證前臺(tái)線程獲取更多的CPU鼎天。

Android異步方式:

  • Thread(直接new不易復(fù)用,頻繁創(chuàng)建開(kāi)銷(xiāo)大)
  • HandlerThread(串行執(zhí)行暑竟,不斷從隊(duì)列中獲取任務(wù))
  • IntentService(不占用主線程斋射,優(yōu)先級(jí)高,完成就結(jié)束)
  • AsyncTask(線程池但荤,無(wú)需處理線程切換)
  • 線程池(易復(fù)用罗岖、定時(shí)、任務(wù)隊(duì)列腹躁、并發(fā)數(shù)控制)
  • RxJava

注意事項(xiàng):

  • 不要直接new Thread桑包,不易復(fù)用。
  • 線程要有對(duì)應(yīng)的名字纺非,出問(wèn)題時(shí)候容易定位哑了。
  • 線程池要提取公共類(lèi),避免重復(fù)創(chuàng)建占用資源烧颖。
  • 線程注意設(shè)置優(yōu)先級(jí)弱左,合理利用資源。
  • IO密集型任務(wù)不消耗CPU倒信,可以創(chuàng)建大的核心池科贬。
  • CPU密集型則需要少于CPU核心數(shù),對(duì)CPU占用較大鳖悠。

網(wǎng)絡(luò)優(yōu)化

工具:

  • Network Profiler
  • 抓包工具(Charles榜掌,F(xiàn)iddler,Wireshark乘综,TcpDump)
  • TrafficStats
  • NetworkStatsManager

技巧:

  • 數(shù)據(jù)緩存憎账,設(shè)置過(guò)期時(shí)間,避免重新獲取卡辰。
  • 加上版本判斷胞皱,只獲取有變化的數(shù)據(jù)邪意。
  • 數(shù)據(jù)壓縮,GZip壓縮反砌。
  • 圖片壓縮雾鬼,縮略圖展示,使用webP格式宴树。
  • 合并請(qǐng)求策菜,減少次數(shù)。
  • DNS優(yōu)化(阿里云)酒贬。
  • 協(xié)議版本升級(jí)又憨。
    http/0.9版本:1991年,原型版本,功能簡(jiǎn)陋锭吨,只有一個(gè)命令GET,只支持純文本內(nèi)容蠢莺,該版本已過(guò)時(shí)。
    http/1.0版本: 1996年5月,支持cache, MIME, method等零如。
    http/1.1版本: 1997年1月,默認(rèn)建立持久連接躏将,并能很好地配合代理服務(wù)器工作。還支持以管道方式在同時(shí)發(fā)送多個(gè)請(qǐng)求考蕾,以便降低線路負(fù)載耸携,提高傳輸速度。
    http/2 版本: 2015年5月作為互聯(lián)網(wǎng)標(biāo)準(zhǔn)正式發(fā)布,頭部信息和數(shù)據(jù)體都是二進(jìn)制辕翰,引入頭信息壓縮機(jī)制等。

電量?jī)?yōu)化

工具:

  • BatteryManager
  • Battery Historian
  • PowerManager.WakeLock

方案:

  • 特別注意視頻播放狈谊。
  • 傳感器使用喜命。
  • 線程使用(AOP Run方法)。
  • 定位(考慮網(wǎng)絡(luò)定位代替GPS)等河劝。
  • 使用JobScheduler壁榕。

apk瘦身優(yōu)化

可以在Android Studio里面Build中選擇Analyze APK,看到apk包內(nèi)各個(gè)資源大小赎瞎。

方案:

  • 代碼混淆(Proguard牌里、AndResGuard資源混淆)。
  • 第三方庫(kù)刪減從簡(jiǎn)處理务甥。
  • 避免使用枚舉牡辽,枚舉不僅僅會(huì)造成性能的問(wèn)題,還會(huì)占用大量的內(nèi)存敞临。
  • 刪除無(wú)用代碼使用态辛。
  • 刪除無(wú)用資源文件,圖片壓縮或使用webp格式挺尿。
  • so移除奏黑,abiFilters設(shè)置指定so架構(gòu)炊邦,代碼加載對(duì)應(yīng)so庫(kù)。

列表頁(yè)卡頓優(yōu)化

  • 布局優(yōu)化(減少層級(jí)熟史,異步inflate)馁害。
  • 圖片壓縮(大小、分辨率蹂匹、編碼格式)優(yōu)化碘菜,滑動(dòng)時(shí)候取消加載。
  • 使用viewHolder怒详、convertView復(fù)用炉媒。
  • 耗時(shí)任務(wù)異步處理。
  • 注意字符串拼接昆烁,使用StringBuilder吊骤。

存儲(chǔ)優(yōu)化

  • 異步IO。
  • sp存儲(chǔ)性能差静尼,可用騰訊的MMKV代替白粉。
    MMKV 是基于 mmap 內(nèi)存映射的 key-value 組件,底層序列化/反序列化使用 protobuf 實(shí)現(xiàn)鼠渺,性能高鸭巴,穩(wěn)定性強(qiáng)。

WebView優(yōu)化

  • VasSonic:騰訊開(kāi)源的拦盹、解決webview首屏提速的框架鹃祖。
  • WebView在Application中提前初始化,復(fù)用普舆。
  • WebView緩存恬口。
  • 資源文件本地存儲(chǔ)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沼侣,一起剝皮案震驚了整個(gè)濱河市祖能,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛾洛,老刑警劉巖养铸,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異轧膘,居然都是意外死亡钞螟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)谎碍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)筛圆,“玉大人,你說(shuō)我怎么就攤上這事椿浓√” “怎么了闽晦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)提岔。 經(jīng)常有香客問(wèn)我仙蛉,道長(zhǎng),這世上最難降的妖魔是什么碱蒙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任荠瘪,我火速辦了婚禮,結(jié)果婚禮上赛惩,老公的妹妹穿的比我還像新娘哀墓。我一直安慰自己,他們只是感情好喷兼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布篮绰。 她就那樣靜靜地躺著,像睡著了一般季惯。 火紅的嫁衣襯著肌膚如雪吠各。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天勉抓,我揣著相機(jī)與錄音贾漏,去河邊找鬼。 笑死藕筋,一個(gè)胖子當(dāng)著我的面吹牛纵散,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播隐圾,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼困食,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了翎承?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤符匾,失蹤者是張志新(化名)和其女友劉穎叨咖,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體啊胶,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甸各,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了焰坪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趣倾。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖某饰,靈堂內(nèi)的尸體忽然破棺而出儒恋,到底是詐尸還是另有隱情善绎,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布诫尽,位于F島的核電站禀酱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏牧嫉。R本人自食惡果不足惜剂跟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酣藻。 院中可真熱鬧曹洽,春花似錦、人聲如沸辽剧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抖仅。三九已至坊夫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撤卢,已是汗流浹背环凿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留放吩,地道東北人智听。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像渡紫,于是被迫代替她去往敵國(guó)和親到推。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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

  • 為什么要性能優(yōu)化惕澎? 因?yàn)槭謾C(jī)CPU和內(nèi)存受到限制,過(guò)多使用內(nèi)存會(huì)可能會(huì)導(dǎo)致內(nèi)存溢出莉测、過(guò)度使用CPU可能會(huì)導(dǎo)致手機(jī)卡...
    Harrison_CSL閱讀 420評(píng)論 0 2
  • 注意事項(xiàng): 布局優(yōu)化;盡量使用include唧喉、merge捣卤、ViewStub標(biāo)簽,盡量不存在冗余嵌套及過(guò)于復(fù)雜布局(...
    HarryXR閱讀 5,168評(píng)論 1 19
  • 性能優(yōu)化屬于一個(gè)老生常談的話題八孝,性能的優(yōu)化直觀角度上主要體現(xiàn)在UI的流暢程度董朝、運(yùn)行的穩(wěn)定性、代碼質(zhì)量和安裝包的體積...
    DoneWillianm閱讀 1,235評(píng)論 0 1
  • 一干跛、前言: 用android的都知道子姜,新買(mǎi)的手機(jī)用過(guò)一段時(shí)間后,手機(jī)變得越來(lái)越卡了楼入;裝了一些APP后哥捕,電量用得飛快...
    因?yàn)槲业男?/span>閱讀 1,352評(píng)論 2 19
  • 鹽_bebc閱讀 228評(píng)論 0 3