關(guān)于Android性能優(yōu)化拯坟,該從哪些方面入手但金?

Android設(shè)備作為一種移動設(shè)備,無論是內(nèi)存還是CPU的性能都受到了很大的限制郁季,這導(dǎo)致Android程序的性能問題異常突出冷溃,對于性能優(yōu)化提出了更高的要求。本篇文章根據(jù)Android開發(fā)中一些有效的性能優(yōu)化方法梦裂,貼出一些關(guān)于性能優(yōu)化方面的技術(shù)文章似枕,為Android開發(fā)中有關(guān)性能優(yōu)化方面的學(xué)習(xí)提供一個參考。

一年柠、Android性能優(yōu)化的方面

參考:《Android開發(fā)藝術(shù)探索》

針對Android的性能優(yōu)化凿歼,主要有以下幾個有效的優(yōu)化方法:

1.布局優(yōu)化

2.繪制優(yōu)化

3.內(nèi)存泄漏優(yōu)化

4.響應(yīng)速度優(yōu)化

5.ListView/RecycleView及Bitmap優(yōu)化

6.線程優(yōu)化

7.其他性能優(yōu)化的建議

下面我們具體來介紹關(guān)于以上這幾個方面優(yōu)化的具體思路及解決方案。

二冗恨、布局優(yōu)化

關(guān)于布局優(yōu)化的思想很簡單答憔,就是盡量減少布局文件的層級。這個道理很淺顯掀抹,布局中的層級少了虐拓,就意味著Android繪制時的工作量少了,那么程序的性能自然就提高了傲武。

如何進行布局優(yōu)化蓉驹?

①刪除布局中無用的控件和層次城榛,其次有選擇地使用性能比較低的ViewGroup。

關(guān)于有選擇地使用性能比較低的ViewGroup,這就需要我們開發(fā)就實際靈活選擇了戒幔。

例如:如果布局中既可以使用LinearLayout也可以使用RelativeLayout吠谢,那么就采用LinearLayout,這是因為RelativeLayout的功能比較復(fù)雜诗茎,它的布局過程需要花費更多的CPU時間工坊。FrameLayout和LinearLayout一樣都是一種簡單高效的ViewGroup,因此可以考慮使用它們敢订,但是很多時候單純通過一個LinearLayout或者FrameLayout無法實現(xiàn)產(chǎn)品效果王污,需要通過嵌套的方式來完成。這種情況下還是建議采用RelativeLayout,因為ViewGroup的嵌套就相當(dāng)于增加了布局的層級楚午,同樣會降低程序的性能昭齐。

②采用<include>標簽,<merge>標簽,ViewStub。

<include>標簽主要用于布局重用矾柜。

<merge>標簽一般和<include>配合使用阱驾,可以降低減少布局的層級。

ViewStub提供了按需加載的功能怪蔑,當(dāng)需要時才會將ViewStub中的布局加載到內(nèi)存里覆,提高了程序初始化效率。

關(guān)于它們的使用方法缆瓣,參考:Android布局優(yōu)化之include喧枷、merge、ViewStub的使用

③避免多度繪制

過度繪制(Overdraw)描述的是屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次弓坞。在多層次重疊的 UI 結(jié)構(gòu)里面隧甚,如果不可見的 UI 也在做繪制的操作,會導(dǎo)致某些像素區(qū)域被繪制了多次渡冻,同時也會浪費大量的 CPU 以及 GPU 資源戚扳。

如下所示,有些部分在布局時族吻,會被重復(fù)繪制帽借。


關(guān)于過度繪制產(chǎn)生的一般場景及解決方案,參考:Android 過度繪制優(yōu)化

三呼奢、繪制優(yōu)化

繪制優(yōu)化是指View的onDraw方法要避免執(zhí)行大量的操作宜雀,這主要體現(xiàn)在兩個方面:

①onDraw中不要創(chuàng)建新的局部對象。

因為onDraw方法可能會被頻繁調(diào)用握础,這樣就會在一瞬間產(chǎn)生大量的臨時對象辐董,這不僅占用了過多的內(nèi)存而且還會導(dǎo)致系統(tǒng)更加頻繁gc,降低了程序的執(zhí)行效率禀综。

②onDraw方法中不要做耗時的任務(wù)简烘,也不能執(zhí)行成千上萬次的循環(huán)操作苔严,盡管每次循環(huán)都很輕量級,但是大量的循環(huán)仍然十分搶占CPU的時間片孤澎,這會造成View的繪制過程不流暢届氢。

按照Google官方給出的性能優(yōu)化典范中的標準,View的繪制頻率保證60fps是最佳的覆旭,這就要求每幀繪制時間不超過16ms(16ms = 1000/60)退子,雖然程序很難保證16ms這個時間,但是盡量降低onDraw方法中的復(fù)雜度總是切實有效的型将。

四寂祥、內(nèi)存泄漏優(yōu)化

內(nèi)存泄漏是開發(fā)過程中的一個需要重視的問題,但是由于內(nèi)存泄露問題對開發(fā)人員的經(jīng)驗和開發(fā)意識有較高的要求七兜,因此也是開發(fā)人員最容易犯的錯誤之一丸凭。

內(nèi)存泄露的優(yōu)化分為兩個方面:

①在開發(fā)過程中避免寫出有內(nèi)存泄漏的代碼

②通過一些分析工具比如MAT來找出潛在的內(nèi)存泄露,然后解決腕铸。

對應(yīng)于兩種不同情況惜犀,一個是了解內(nèi)存泄漏的可能場景以及如何規(guī)避,二是怎么查找內(nèi)存泄漏狠裹。

1.那么我們就先了解什么是內(nèi)存泄漏?這樣我們才能知道如何避免虽界。

大家都知道,java是有垃圾回收機制的酪耳,這使得java程序員比C++程序員輕松了許多浓恳,存儲申請了刹缝,不用心心念念要加一句釋放碗暗,java虛擬機會派出一些回收線程兢兢業(yè)業(yè)不定時地回收那些不再被需要的內(nèi)存空間(注意回收的不是對象本身,而是對象占據(jù)的內(nèi)存空間)梢夯。

Q1:什么叫不再被需要的內(nèi)存空間言疗?

答:Java沒有指針湃缎,全憑引用來和對象進行關(guān)聯(lián)饼丘,通過引用來操作對象。如果一個對象沒有與任何引用關(guān)聯(lián)刷钢,那么這個對象也就不太可能被使用到了人乓,回收器便是把這些“無任何引用的對象”作為目標勤篮,回收了它們占據(jù)的內(nèi)存空間。

Q2:如何分辨為對象無引用色罚?

答:2種方法

引用計數(shù)法直接計數(shù)碰缔,簡單高效,Python便是采用該方法戳护。但是如果出現(xiàn) 兩個對象相互引用金抡,即使它們都無法被外界訪問到瀑焦,計數(shù)器不為0它們也始終不會被回收。為了解決該問題梗肝,java采用的是b方法榛瓮。

可達性分析法這個方法設(shè)置了一系列的“GC Roots”對象作為索引起點,如果一個對象 與起點對象之間均無可達路徑巫击,那么這個不可達的對象就會成為回收對象禀晓。這種方法處理 兩個對象相互引用的問題,如果兩個對象均沒有外部引用坝锰,會被判斷為不可達對象進而被回收(如下圖)匆绣。


Q3:有了回收機制,放心大膽用不會有內(nèi)存泄漏什黑?

答:答案當(dāng)然是No崎淳!

雖然垃圾回收器會幫我們干掉大部分無用的內(nèi)存空間,但是對于還保持著引用愕把,但邏輯上已經(jīng)不會再用到的對象拣凹,垃圾回收器不會回收它們。這些對象積累在內(nèi)存中恨豁,直到程序結(jié)束嚣镜,就是我們所說的“內(nèi)存泄漏”。
當(dāng)然了橘蜜,用戶對單次的內(nèi)存泄漏并沒有什么感知菊匿,但當(dāng)泄漏積累到內(nèi)存都被消耗完,就會導(dǎo)致卡頓计福,崩潰跌捆。

下面這張圖可以幫助我們更好地理解對象的狀態(tài),以及內(nèi)存泄漏的情況



左邊未引用的對象是會被GC回收的象颖,右邊被引用的對象不會被GC回收佩厚,但是未使用的對象中除了未引用的對象,還包括已被引用的一部分對象说订,那么內(nèi)存泄漏久發(fā)生這部分已被引用但未使用的對象抄瓦。

2.Android一般在什么情況下會出現(xiàn)內(nèi)存泄漏?

①集合類泄漏
②單例/靜態(tài)變量造成的內(nèi)存泄漏
③匿名內(nèi)部類/非靜態(tài)內(nèi)部類
④資源未關(guān)閉造成的內(nèi)存泄漏

大概可以分為以上幾類陶冷,還有一些經(jīng)常會聽到的Hanlder,AsyncTask引起內(nèi)存泄漏钙姊,都屬于上述③中的情況。

那么上述四種情況是怎么造成的內(nèi)存泄漏埂伦,具體是什么原因煞额,以及Android中一些知名的引起內(nèi)存泄漏的原因,以及解決方法是怎么樣的?

關(guān)于這部分內(nèi)容立镶,看了一些較好的文章壁袄,向大家推薦一下:

[譯]Android內(nèi)存泄漏的八種可能(上)
[譯]Android防止內(nèi)存泄漏的八種方法(下)
Android 內(nèi)存泄漏總結(jié)

3.Android怎么分析內(nèi)存泄漏?

上面介紹了內(nèi)存泄漏的場景媚媒,對應(yīng)的有一些解決方案嗜逻。

那么在內(nèi)存泄漏已經(jīng)發(fā)生的情況下,我們該如何解決呢缭召?

我們可以通過MAT(Memory Analyzer Tool)栈顷,或者 LeakCanary來檢測Android中的內(nèi)存泄漏。

上面的文章:Android 內(nèi)存泄漏總結(jié) 也介紹了如何使用MAT嵌巷,或者 LeakCanary來檢測Android中的內(nèi)存泄漏萄凤。

這篇文章Android 性能優(yōu)化之使用MAT分析內(nèi)存泄露問題詳細介紹了使用MAT來檢測Android中的內(nèi)存泄漏。

五搪哪、響應(yīng)速度優(yōu)化

響應(yīng)速度優(yōu)化的核心思想就是避免在主線程中做耗時操作靡努。

如果有耗時操作,可以開啟子線程執(zhí)行晓折,即采用異步的方式來執(zhí)行耗時操作惑朦。

如果在主線程中做太多事情,會導(dǎo)致Activity啟動時出現(xiàn)黑屏現(xiàn)象漓概,甚至ANR漾月。


Android規(guī)定,Activity如果5秒鐘之內(nèi)無法響應(yīng)屏幕觸摸事件或者鍵盤輸入事件就會出現(xiàn)ANR胃珍,而BroadcastReceiver如果10秒鐘之內(nèi)還未執(zhí)行完操作也會出現(xiàn)ANR梁肿。

為了避免ANR,可以開啟子線程執(zhí)行耗時操作觅彰,但是子線程不能更新UI吩蔑,所以需要子線程與主線程進行通信來解決子線程執(zhí)行耗時任務(wù)后,通知主線程更新UI的場景缔莲。關(guān)于這部分哥纫,需要掌握Handler消息機制霉旗,AsyncTask痴奏,IntentService等內(nèi)容。

可以看以下內(nèi)容:
Android消息機制的原理及源碼解析
Android中的線程狀態(tài)之AsyncTask詳解
Android多線程全面解析:IntentService用法&源碼

然而厌秒,在實際開發(fā)中读拆,ANR仍然不可避免的發(fā)生了,而且很難從代碼上發(fā)現(xiàn)鸵闪,這時候就要用到ANR日志分析檐晕。當(dāng)一個進程發(fā)生了ANR之后,系統(tǒng)會在/data/anr目錄下創(chuàng)建一個文件traces.txt,通過分析這個文件就能定位出ANR的原因辟灰。

六个榕、ListView/RecycleView及Bitmap優(yōu)化


ListView/RecycleView的優(yōu)化思想主要從以下幾個方面入手:

①使用ViewHolder模式來提高效率

②異步加載:耗時的操作放在異步線程中

③ListView/RecycleView的滑動時停止加載和分頁加載

具體優(yōu)化建議及詳情,參考:ListView的優(yōu)化

Bitmap優(yōu)化


主要是對加載圖片進行壓縮芥喇,避免加載圖片多大導(dǎo)致OOM出現(xiàn)西采。

具體圖片壓縮方案,參考:徹底理解Bitmap的高效加載策略

七继控、線程優(yōu)化

線程優(yōu)化的思想就是采用線程池械馆,避免程序中存在大量的Thread。線程池可以重用內(nèi)部的線程武通,從而避免了線程的創(chuàng)建和銷毀鎖帶來的性能開銷霹崎,同時線程池還能有效地控制線程池的最大并法術(shù),避免大量的線程因互相搶占系統(tǒng)資源從而導(dǎo)致阻塞現(xiàn)象的發(fā)生冶忱。因此在實際開發(fā)中尾菇,盡量采用線程池,而不是每次都要創(chuàng)建一個Thread對象囚枪。

關(guān)于線程池詳解及使用错沽,參考:Java線程池詳解

八眶拉、其他性能優(yōu)化建議

①避免過度的創(chuàng)建對象

②不要過度使用枚舉千埃,枚舉占用的內(nèi)存空間要比整型大

③常量請使用static final來修飾

④使用一些Android特有的數(shù)據(jù)結(jié)構(gòu),比如SparseArray和Pair等

⑤適當(dāng)采用軟引用和弱引用

⑥采用內(nèi)存緩存和磁盤緩存

⑦盡量采用靜態(tài)內(nèi)部類忆植,這樣可以避免潛在的由于內(nèi)部類而導(dǎo)致的內(nèi)存泄漏放可。

以上是關(guān)于Android性能優(yōu)化方面,我們一些入手點朝刊。從這些方面耀里,我們可以在平時的開發(fā)中注意,避免類似錯誤拾氓,提高Android程序的性能冯挎,但是其中一些方面的要求則需要我們不斷的學(xué)習(xí),以及平時良好的意識與習(xí)慣咙鞍。由于自己開發(fā)經(jīng)驗幾乎為0房官,沒辦法根據(jù)實際經(jīng)驗來說明,只能寫下這篇文章來提醒自己以后開發(fā)的時候需要注意和培養(yǎng)的地方续滋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翰守,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疲酌,更是在濱河造成了極大的恐慌蜡峰,老刑警劉巖了袁,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異湿颅,居然都是意外死亡载绿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門油航,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卢鹦,“玉大人,你說我怎么就攤上這事劝堪〖阶裕” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵秒啦,是天一觀的道長熬粗。 經(jīng)常有香客問我,道長余境,這世上最難降的妖魔是什么驻呐? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮芳来,結(jié)果婚禮上含末,老公的妹妹穿的比我還像新娘。我一直安慰自己即舌,他們只是感情好佣盒,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顽聂,像睡著了一般肥惭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上紊搪,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天蜜葱,我揣著相機與錄音,去河邊找鬼耀石。 笑死牵囤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的滞伟。 我是一名探鬼主播揭鳞,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诗良!你這毒婦竟也來了汹桦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鉴裹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體径荔,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡督禽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了总处。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狈惫。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鹦马,靈堂內(nèi)的尸體忽然破棺而出胧谈,到底是詐尸還是另有隱情,我是刑警寧澤荸频,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布菱肖,位于F島的核電站,受9級特大地震影響旭从,放射性物質(zhì)發(fā)生泄漏稳强。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一和悦、第九天 我趴在偏房一處隱蔽的房頂上張望退疫。 院中可真熱鬧,春花似錦鸽素、人聲如沸褒繁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澜汤。三九已至,卻和暖如春舵匾,著一層夾襖步出監(jiān)牢的瞬間俊抵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工坐梯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留徽诲,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓吵血,卻偏偏與公主長得像谎替,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蹋辅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

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