Android性能優(yōu)化總結

本文大體分為四部分
  1. 內(nèi)存優(yōu)化
  2. 布局優(yōu)化
  3. 編碼優(yōu)化
  4. 網(wǎng)絡優(yōu)化

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

主要參考胡凱文章

首先說一下內(nèi)存泄漏和OOM:
  1. 內(nèi)存泄漏,因為不恰當?shù)囊脤е卤驹摫会尫诺馁Y源無法得到釋放。
  2. OOM,新分配的內(nèi)存大小加上已經(jīng)占用的內(nèi)存大小,超出了限制的內(nèi)存大小木张。

內(nèi)存泄漏更多是因為我們的代碼寫的有問題,OOM更多是因為我們對我們應用內(nèi)存的占用沒有很好的把控。內(nèi)存泄漏是導致OOM的一大元兇刃滓。

內(nèi)存優(yōu)化分為5點來說:
  1. 減少對象內(nèi)存占用
  2. 內(nèi)存對象的復用
  3. 避免內(nèi)存泄漏
  4. 合理的內(nèi)存使用策略
  5. 內(nèi)存優(yōu)化輔助工具

一、減少對象內(nèi)存占用

  1. 使用更加輕量的數(shù)據(jù)結構耸弄。比如:ArrayMap/SparseArray是替代HashMap的好幫手咧虎。關于ArrayMap和SparseArray的使用:
  • 適合對象個數(shù)的數(shù)量級最好在千以內(nèi),因為他們的插入和刪除的效率不夠高计呈。
  • 查找和插入使用的是二分查找砰诵。
  • key類型是int時,請使用SparseArray因為它避免了自動裝箱捌显。
  1. 避免使用Enum茁彭。官方說法是,相對于靜態(tài)常量扶歪,枚舉會消耗兩倍以上的內(nèi)存理肺。并且在運行時還會產(chǎn)生額外的內(nèi)存占用。在一個官方實例里善镰,枚舉占用的內(nèi)存是靜態(tài)常量的13倍妹萨,運行時內(nèi)存占用是6倍。
  2. 減少Bitmap對象的內(nèi)存占用炫欺。對于創(chuàng)建出來的Bitmap對象通常有兩個操作可以優(yōu)化其內(nèi)存占用乎完。
  • inSampleSize:在載入內(nèi)存之前,計算一個合適的縮放比例品洛。
  • decode format:解碼格式树姨,ARGB_8888(每個像素4個字節(jié),最高精度毫别,有透明通道)娃弓、RGB_565(每個像素兩個字節(jié),無透明度)岛宦、ARGB_4444(deprecated in Api13)台丛、Alpah_8,不同的解碼格式差別很大。根據(jù)情況選擇合適的會比較好挽霉。
  1. 使用更小的圖片防嗡。拿到美工給的圖,要留意大圖直接被XML引用有時會出現(xiàn)InflationException侠坎,該異常的根本原因就是OOM蚁趁。

二、內(nèi)存對象的復用

  1. 復用系統(tǒng)自帶的資源实胸。系統(tǒng)自帶了很多顏色他嫡、動畫、樣式庐完、布局钢属、圖片。使用這些可以減少內(nèi)存開銷门躯,但需注意版本差異性淆党。
  2. ListView/GridView/RecyclerView內(nèi)重復子View的復用。
  3. Bitmap對象復用讶凉。使用inBitmap來復用已經(jīng)存在的內(nèi)存區(qū)域染乌。3.0之后出現(xiàn),重用的bitmap大小和解碼格式需要一致懂讯。4.4以后優(yōu)化大小限制荷憋,只要小于或等于原bitmap的大小即可∮虼迹可以維護一個有多種典型bitmap的對象池台谊,使得后續(xù)bitmap創(chuàng)建都可以找到合適的復用模板。
  4. 在頻繁調(diào)用的方法外創(chuàng)建對象譬挚。如onDraw()方法會頻繁調(diào)用,在里面做創(chuàng)建對象的操作會迅速增加內(nèi)存使用酪呻,很容易引起頻繁GC甚至是內(nèi)存抖動减宣。
  5. StringBuilder/StringBuffer。使用StringBuilder/StringBuffer來替代頻繁的字符串拼接操作玩荠。

三漆腌、避免內(nèi)存泄漏

  1. Activity的泄漏。
  • 內(nèi)部類引用導致阶冈。典型的如Handler闷尿。考慮盡量使用靜態(tài)內(nèi)部類女坑,同時使用弱引用機制避免互相引用出現(xiàn)的泄漏。
  • Activity Context被傳遞到其他實例中,可能導致自身被引用發(fā)生泄漏臂港。盡量使用Application Context。除了和UI相關的誉简,如顯示彈窗、啟動Activity盟广、填充布局闷串。參考Android Context。
  1. 臨時Bitmap對象的回收筋量。臨時創(chuàng)建一個相對比較大的bitmap對象烹吵,在經(jīng)過變換獲得新的bitmap對象之后,應盡快回收之前的bitmap桨武。注意createBitmap()方法可能返回source bitmap年叮,所以需要檢查返回值是否和source bitmap相等。不等才可以對source bitmap執(zhí)行recycle方法玻募。
  2. 監(jiān)聽器的注銷只损。
  3. Cursor對象的及時關閉。
  4. 緩存容器的對象泄漏七咧。如4.0之前跃惫,把drawable添加到緩存容器,因為drawable和view的強引用很容易導致activity發(fā)生泄漏艾栋。
  5. WebView的泄露爆存。Android的WebView存在很大的兼容性問題,WebView因為不同系統(tǒng)版本不同廠商都粗乃很大的差異蝗砾,甚至標準的WebView存在內(nèi)存泄漏的問題(09年發(fā)現(xiàn)先较,13年修復)。根治方法:為WebView使用新進程悼粮,通過AIDL進行通信闲勺,WebView所在進程根據(jù)業(yè)務需要在合適時機進行銷毀。
  6. 慎用static對象扣猫,static的生命周期和應用的進程保持一致菜循,使用不當很可能導致內(nèi)存泄漏。
  7. 留意單例對象中不合理的引用申尤。單例對象的生命周期和應用保持一致癌幕。

四、合理的內(nèi)存使用策略

  1. 使用IntentService代替Service昧穿。
  2. 謹慎使用large heap勺远。在清單文件的<application>節(jié)點設置largeHeap=true可以為應用生命一個更大的heap控件。會影響用戶體驗时鸵,并使GC運行時間更長胶逢,任務切換耗能增加。并且,在一些嚴格限制的機器上宪塔,largeHeap和通常的heap size大小一樣磁奖。你始終應該通過getMemoryClass()來檢查實際獲取到的heap大小。
  3. 合適的緩存大小某筐。結合可用內(nèi)存大小等因素設置比搭。
  4. onLowMemory()和onTrimMemory()。后者從4.0開始提供南誊,提供了更為詳細的系統(tǒng)內(nèi)存占用級別身诺。可以通過監(jiān)測系統(tǒng)內(nèi)存占用適當?shù)尼尫抛陨淼囊恍﹥?nèi)存占用抄囚。
  5. 選擇合適的文件夾存放資源文件霉赡。圖片會被拉伸以適應不同的設備。對于不希望被拉伸的圖片幔托,放在assets或nodpi目錄下穴亏。
  6. 對大內(nèi)存分配做Try...Catch...操作。比如給解析大圖時重挑,使用try catch嗓化,catch到OOM后將采樣比例增加一倍再次嘗試解析。
  7. 慎用抽象編程谬哀。抽象需要同等量的代碼用于可執(zhí)行刺覆,這些代碼會被mapping到內(nèi)存中。
  8. 使用nano protobufs序列化數(shù)據(jù)史煎。Google設計谦屑,類似XML,比XML更加輕量快速簡單篇梭。
  9. 慎用依賴注入氢橙。通過掃描你的代碼執(zhí)行許多初始化操作,會導致你的代碼需要大量的內(nèi)存空間來mapping代碼很洋,而且mapped pages會長時間保留在內(nèi)存中充蓝。
  10. 慎用多進程『泶牛可以擴大應用的內(nèi)存占用范圍,但使用不當會導致顯著增加內(nèi)存官脓。
  11. 使用ProGuard剔除不需要的代碼协怒。
  12. 慎用第三方庫。很多功能會用不上卑笨。

五孕暇、內(nèi)存優(yōu)化輔助工具

  1. facebook開源的LeakCanary,可用來監(jiān)測內(nèi)存泄漏
  2. Android Monitor,可以查看內(nèi)存占用妖滔,可以查看指向隧哮,可以手動觸發(fā)GC。分析內(nèi)存泄漏的流程是
  3. 手動觸發(fā)GC
  4. 查看JavaHeap
  5. 點擊Analyzer Task即可進行內(nèi)存泄漏的分析座舍。

布局優(yōu)化

分四個方面

  1. 選擇合適的根節(jié)點
  2. 重用布局文件
  3. 僅在需要時加載布局
  4. 避免過度繪制

一沮翔、選擇合適的根節(jié)點

Android在創(chuàng)建Activity時默認生成的布局為RelativeLayout,而新建布局時默認的根節(jié)點為LinearLayout曲秉。這是因為

  1. 在復雜的布局中使用RelativeLayout可以降低布局嵌套采蚀,使布局比較扁平。也更加靈活承二。
  2. 對于簡單的布局榆鼠,LinearLayout在不用處理weight屬性的情況下,性能上是優(yōu)于至少需要計算兩次的RelativeLayout的亥鸠。

二妆够、重用布局文件

  1. <include>標簽的使用,要注意如果需要使用layout屬性负蚊,必需先設置layout:width和layout:height
  2. <merge>標簽的使用可減少不必要的視圖嵌套 :
  3. 添加的子視圖不需要針對父視圖的屬性神妹,只是要添加到父視圖上顯示。根節(jié)點可為<merge>盖桥。
  4. 比如在LinearLayout里include另外一個方向相同的LinearLayout灾螃,這個被include的視圖的根節(jié)點就可以改為merge.

三、僅在需要時加載布局

<ViewStub>
使用時調(diào)用inflate即可揩徊,也可以調(diào)用setVisibility(View.VISIBILITY)腰鬼。
注意:不支持<merge>標簽的布局。

四塑荒、避免過度繪制

比如給根布局設置了圖片背景熄赡,但是用戶只能看到子View,根本就沒有看到最下面的背景齿税。但是背景仍要被繪制彼硫。這就是過度繪制。
可以通過設置-開發(fā)者選項-顯示GPU過度繪制來觀察過度繪制凌箕。顏色越深的區(qū)域過度繪制越嚴重拧篮,藍色最好,紅色最差牵舱。

  1. 去除不必要的背景設置串绩。
  2. 自定義view時,通過Canvas的clipRect()來繪制部分需要重繪的區(qū)域芜壁。

五礁凡、小知識點

  • android:drawableXXX屬性高氮。TextView控件可直接顯示圖片和文字。
  • setCompoundDrawable()顷牌,代碼中通過該方法實現(xiàn)第一個效果剪芍。
  • android:divider,使用自帶的分割線窟蓝。
  • space控件罪裹,可用于添加空白間隔,該控件不進行繪制疗锐。
  • android:lineSpacingExtra="",android:text="aaa\nbbb\nccc"多行文字可使用TextView的行間距實現(xiàn)坊谁。
  • Spannable,使用Spannable來為TextView設置強大的樣式滑臊。

編碼優(yōu)化

幾個點

  1. 靜態(tài)方法口芍。將一項通用的功能寫成靜態(tài)方法,調(diào)用速度會提升15%-20%雇卷,同時不需要創(chuàng)建對象來調(diào)用該方法鬓椭,也不用擔心改變對象的狀態(tài)(靜態(tài)方法無法訪問非靜態(tài)字段)。
  2. 避免創(chuàng)建不必要的對象
  3. 靜態(tài)最終常量关划。對基本數(shù)據(jù)類型以及String常量使用static final修飾小染,會在dex文件的初始化器中進行初始化,會更快贮折。
  4. 多使用增強型for循環(huán)裤翩,但ArrayList使用傳統(tǒng)循環(huán)方式。
  5. 使用系統(tǒng)封裝好的API调榄。系統(tǒng)的API很多功能是通過底層匯編模式執(zhí)行的踊赠,效率會比較高。如數(shù)組拷貝的功能每庆,使用System.arrayCopy()會比使用循環(huán)一一賦值效率高9倍以上筐带。
  6. 避免在內(nèi)部使用getter/setter。內(nèi)部使用時缤灵,字段查找比方法調(diào)用效率高伦籍。

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

工具:Android Studio有Network Monitor

主要有:

  1. 接口設置多樣化,便于App可以以較少的請求來完成業(yè)務需求腮出。
  2. 使用Gzip壓縮request和response帖鸦,減少數(shù)據(jù)傳輸大小
  3. 可以使用Protocol Buffer來代替json、XML等
  4. 合適的圖片胚嘲。獲取圖片時告知服務器寬高質(zhì)量等來獲取合適的圖片資源富蓄。
  5. 設置網(wǎng)絡緩存,來取消不必要的網(wǎng)絡請求慢逾。
  6. 在網(wǎng)絡良好的時候立倍,對一些很有可能會進行操作的數(shù)據(jù)進行提前獲取。
  7. 弱網(wǎng)優(yōu)化侣滩,Android Emulator可以設置網(wǎng)絡速度和延遲來做弱網(wǎng)測試口注。可采取的措施如:不自動加載圖片君珠、先反饋后提交(如用戶點贊寝志,先給提交成功的反饋,記錄下來之后提交)
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末策添,一起剝皮案震驚了整個濱河市材部,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唯竹,老刑警劉巖乐导,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浸颓,居然都是意外死亡物臂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門产上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棵磷,“玉大人,你說我怎么就攤上這事晋涣∫敲剑” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵谢鹊,是天一觀的道長算吩。 經(jīng)常有香客問我,道長撇贺,這世上最難降的妖魔是什么赌莺? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮松嘶,結果婚禮上艘狭,老公的妹妹穿的比我還像新娘。我一直安慰自己翠订,他們只是感情好巢音,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尽超,像睡著了一般官撼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上似谁,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天傲绣,我揣著相機與錄音掠哥,去河邊找鬼。 笑死秃诵,一個胖子當著我的面吹牛续搀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播菠净,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼禁舷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毅往?” 一聲冷哼從身側響起牵咙,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎攀唯,沒想到半個月后洁桌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡革答,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年战坤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片残拐。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡途茫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出溪食,到底是詐尸還是另有隱情囊卜,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布错沃,位于F島的核電站栅组,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枢析。R本人自食惡果不足惜玉掸,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望醒叁。 院中可真熱鬧司浪,春花似錦、人聲如沸把沼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饮睬。三九已至租谈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捆愁,已是汗流浹背割去。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工窟却, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人劫拗。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓间校,卻偏偏與公主長得像,于是被迫代替她去往敵國和親页慷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

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