Android進階之路——應用開發(fā)模塊的性能優(yōu)化

說起Android的性能優(yōu)化,其實是一個很大的范疇笛粘,說到深入的就是架構師級別的。但是對很對初中級的Android開發(fā)工程師們經(jīng)常遇到——

用戶say郑兴,什么狗屎,刷這么久都沒反應贝乎,取關卸載算了情连。又或者是老板拍板了,施壓給CTO览效,然后CTO又來找你:Y的今天必須給我想辦法優(yōu)化了却舀,不然不準回家。

參考40 Developer Tips for Android Optimization

那為什么從UI的表象上看朽肥,App又卡又慢而且還錯亂禁筏。基于這些衡招,leo就給大家整理出一些能輕易掌握一些應用開發(fā)中用到的性能優(yōu)化技巧篱昔,從而輕松應對這些情況。

UI.png

一始腾、UI層

首先要明白的是UI的繪制流程:measure-layout-draw州刽,measure與layout都需要for loop所有的子控件,匯集起來才能完成繪制浪箭,布局穗椅。所以子控件越多,所消耗的時間越長(inflate奶栖,layout_weight匹表,relative,多層嵌套等)宣鄙,減少不必要的子控件或層級袍镀,是相當有必要的。你可以通過merge,viewstub這些標簽來減少層級嵌套冻晤。如果你的空間觀念沒那么好苇羡,可以用HierarchyViewer工具來檢查。

  1. 復用item鼻弧,會更輕松设江。對于Listview或者GridView這種多item的組件來說,復用item可以減少inflate次數(shù)攘轩,通過setTag叉存,getTag的ViewHolder方式實現(xiàn)復用,這里要注意的是度帮,holder中的控件最好reset后再賦值鹉胖,避免圖片,文字錯亂。

  2. 讓空白空間大于圖像空間甫菠,讓圖像空間大于按鈕的大小。如果將按鈕冕屯,多選框寂诱,切換控件放大后是很丑陋的。一個100dip(0.63")大小的按鈕是不想在平板上顯示為原來兩倍寬度200dip(1.25")的.原因是屏幕變大了安聘,這不是說平板是給巨人用的痰洒。我們可以這樣做,在按鈕增加的空間和圖片擴展的空間里添加空白浴韭。

  3. pager最好不要預加載丘喻。對于ViewPager第一次顯示時卡頓以及左右滑動卡頓,有以下幾種優(yōu)化方式念颈。

  • 同時緩存page數(shù)最好為最小值3泉粉,如果過多,那么第一次顯示時榴芳,ViewPager所初始化的pager就會很多嗡靡,這樣pager累積渲染耗時就會增多,看起來就卡窟感。

  • 每個pager應該只在顯示時才加載網(wǎng)絡或數(shù)據(jù)庫(UserVisibleHint=true)讨彼,最好不要預加載數(shù)據(jù),以免造成浪費柿祈。

  1. 用GraphicalLayout工具快速預覽哈误。GraphicalLayout是WYSIWG XML編輯器。我喜歡直接編寫元素-而不是拖躏嚎,丟棄的可見編程方式蜜自,但在添加一些元素之后,可以在GraphicalLayout的下拉選擇菜單里選擇不同屏幕尺寸進行測試紧索。

    Paste_Image.png

  2. Selectors是創(chuàng)建buttons的利器袁辈。我們在上面提到了如何在XML里定義button的背景,但是你將如何創(chuàng)建一個當按下去會改變的button呢珠漂?很簡單:像下面那樣在xml文件里定義背景晚缩。該xml文件將接收到button當前狀態(tài)并且在外觀上做出相應的改變。

  3. 在Honeycomb之前的版本里時不存在ActionBar跟很多animation樣式的媳危,所以可以使用ActionBarSherlock 跟NineOldAndroids來代替荞彼。Jake Wharton寫的Android開源 組件都是往下兼容的精心杰作。更為驚喜的是待笑,ABS 擁有強大的功能用來定義ActionBar鸣皂。

二、圖片

圖片顯示不出來或者加載時間太長,怎么辦寞缝?分兩部分癌压,加載速度,下載速度荆陆。

對于加載速度滩届,我們要知道一點,雖然下載的圖片可能只有幾百K被啼,但是decode成bitmap所占用的內(nèi)存可是成倍的帜消,盡可能的減小圖片size是根本因素,讓服務端提供不同分辨率的圖片才是最好的解決方案浓体,內(nèi)存總有耗盡的時刻泡挺,別老想著大分辨率會更清晰,實際就只有150&150的空間命浴,非給弄張1000&1000的圖片是不恰當?shù)穆γāA硗庹摷虞d速度:內(nèi)存>硬盤>網(wǎng)絡,合理的使用內(nèi)存緩存也是關鍵咳促。假如自己寫不好稚新,沒關系,有那么多開源的圖片緩存框架跪腹,不用自己操心褂删。

對于下載,要控制好同時下載的最大任務數(shù)(平均速度慢)冲茸,同時給InputStream再包一層緩沖流會更快(如BufferedInputStream)屯阀。

  1. 不要把所有的圖片都縮放了。用布局文件來適應不同屏幕尺寸的方法只是成功的一半轴术,布局里的元素(如:圖片)也要能在高分辨率的屏幕下良好工作难衰。在概念上比較簡單的方式就是創(chuàng)建一套完整的圖片目錄并將它們與很多drawable目錄匹配起來。
    drawable-sw600dp-ldpi drawable-sw600dp-mdpi drawable-sw600dp-hdpi drawable-sw600dp-xhdpi drawable-sw600dp-xxhdpi ...其它的類似逗栽。 但是實際就不要太盡信書了盖袭。 一般來說有drawble-ldpi, drawable-hdpi等目錄就足夠了,不需要將所有的情況都加上彼宠。

  2. 避免使用位圖(jpg,png)鳄虱。對于一些圖標來說,用位圖是個不錯的選擇凭峡,因為它們使用簡單拙已。但是如果可以避免使用位圖,你可以節(jié)省很多空間摧冀。但用不同的方法也可以達到很好的結果倍踪。

  3. 用XML繪圖系宫。位圖都可以用XML繪圖來代替的。XML繪圖不是萬能的建车,但是它的方便性還是使我感到驚訝扩借。你可以在布局文件的任何地方來引用,而且它可以適應于任何屏幕癞志。用它可以做出理想的按鈕往枷。如果必須,就用位圖凄杯。

  4. 通過覆蓋onDraw()創(chuàng)建自定義views. 有些事情XML并不十分在行,我們在OpenSignal和WeatherSignal中畫過許多圖像秉宿,為此有許多的庫戒突,但是我們要為自定義圖像自己編寫代碼。這很有趣描睦〔泊妫或許你永遠也不需要做這個,但為了使圖像高度動態(tài)并自定義忱叭,這經(jīng)常是唯一可行的辦法隔崎。

  5. 在不能使用XML的地方使用SVG. 有時候覆蓋onDraw()并勤勤懇懇的為自定義view編寫代碼畫出需要的線條與弧線是過于技術化了。畢竟有一種矢量圖像語言韵丑,它稱作…Scalable Vector Graphics(可擴展矢量圖形)爵卒。它也是史上最酷的Android應用之一—Androidify的動力來源。事實上他們創(chuàng)建這個庫就是為了那款應用撵彻,他們將它發(fā)布在這里:SVG for Android 钓株。

  6. 對SVG文件GZip壓縮。將它們變得更小它們就會處理的更快陌僵。 但是SVG庫并不是支持一切轴合。在一些特定的alpha通道中似乎不能正常工作,你甚至不得不在代碼中將它們剔除碗短。

  7. 如果要用PNG受葛,最好優(yōu)化一下(用PNGCrush或ImageOptim)

三、運行速度

在運行慢的手機上測試偎谁。你將在運行慢的手機上發(fā)現(xiàn)很多問題总滩,同時它讓你抓狂,沒人會喜歡運行慢的程序搭盾。盡量精簡你的代碼咳秉,你寫的層級與解析越多,就意味著系統(tǒng)需要花更多的時間鸯隅。

  1. 盡量減少XML布局層次澜建。更多的層次意味著系統(tǒng)將為解析你的代碼付出更多的工作向挖,這將會讓圖像渲染的更慢。用<merge>可以幫助你減少視圖層次結構炕舵。這是一種簡單的方式來去除多余的層次何之。好的文章都對此有所解釋,而且在 Android Developer中它也顯得與眾不同咽筋。

  2. 用Android Lint溶推。在工程目錄上右鍵選擇Eclipse>Android Tools>Run Lint。它將會得到程序的一些信息奸攻,并能提高程序的運行速度蒜危,或者它能讓你得代碼更加清爽。它可以給你的代碼提供很詳細的信息睹耐,并在你出錯之前就可以給做出提示辐赞。

  3. 用HierarchyViewer可以直觀的看到你布局的層次。這個智能的工具可以顯示布局中有多少層次硝训,而且可以提示出那些可以讓程序變慢响委。

  4. 如果可以盡量用RelativeLayout。AbsoluteLayout已經(jīng)過期了窖梁,就不要用了赘风。你經(jīng)常會遇到在RelativeLayout和LinearLayout中做出選擇的情況,那就直接用RelativeLayouot吧纵刘,因為它可以讓你減少視圖層次邀窃。
    第二個表單比第一個難看的多。事實上彰导,我們已經(jīng)介紹過一個完整的新元素了蛔翅。但是假如我們要給每個盒子里加入一個圖片,一般的我們將這樣做:盒子 A 在屏幕左半邊 圖片|盒子 B在屏幕右半邊 圖片用第一中方法位谋,你得創(chuàng)建一個有兩個層次的LinearLayout山析,如果用第二種方法,你可以直接在同一個RelativeLayout中加入圖片掏父,比如要指定第一個圖片必須在“dummy_center”的左邊笋轨,而且一個TextView A必須也在其左側。那么你就得用7個元素3個視圖層次了(LinearLayout 方式)赊淑,而(RelativeLayout方式)只用6個元素2個層次爵政,這樣所有的工作添加完成。

    Paste_Image.png

  5. 用一些擴展工具如DDMS陶缺。這可以幫助你發(fā)現(xiàn)一些不必要的網(wǎng)絡調(diào)用钾挟、查看電池使用量、垃圾回收信息饱岸,狀態(tài)變化(例子:當回調(diào)onStop和onDestroy時)等掺出。LittleEye是我目前比較喜歡的工具徽千。

  6. 用AsyncTasks。Anroid工程團隊受夠了人們經(jīng)常在UI線程里面實現(xiàn)網(wǎng)絡調(diào)用(譯注:耗時操作汤锨,容易阻塞UI刷新)双抽,所以他們實現(xiàn)了一些可產(chǎn)生編譯級錯誤信息的API。但是仍然在很多app中的一些工作會拖垮UI線程闲礼,我們要考慮到UI布局要快以及提高UI的響應性牍汹。

四、緩存與網(wǎng)絡

有很多種緩存方式柬泽,也不用leo列舉了慎菲,我們要說的是搭配使用。優(yōu)化可不是一個人的事锨并,實現(xiàn)一個功能簡單钧嘶,但是想優(yōu)化重構,那是很不容易的事琳疏。需要多方面的預判與聯(lián)調(diào)。合理的假設與實踐是優(yōu)化最重要的手段闸拿。

  1. 軟引用空盼、弱引用。 比方說新荤,以前我們一直在用強引用揽趾,HashMap,后來我們發(fā)現(xiàn)占內(nèi)存苛骨,我們就用軟引用篱瞎,弱引用來及時回收,再后來因為回收機制不可控痒芝,所以又有了lrucache俐筋,disklrucache通過算法來平衡內(nèi)存與硬盤緩存。隨著android版本的推進與演化严衬,我們也應該擁抱變化澄者。如果你的App里還有軟引用,弱引用的地方请琳,不妨再check下粱挡。

  2. 網(wǎng)絡+數(shù)據(jù)庫。網(wǎng)絡我們一般都是去主動獲取俄精,而非被動接受询筏。那如果說數(shù)據(jù)是重復的或者未更改的呢?那我們?nèi)ト∫淮尉W(wǎng)絡數(shù)據(jù)有什么意義呢竖慧?我的解決方案是給每個activity或fragment或每個組件設置一個最大請求間隔嫌套,比如一個listview逆屡,第一次請求數(shù)據(jù)時,保存一份到數(shù)據(jù)庫灌危,并記下時間戳康二,當下次重新初始化時,判斷是否超過最大時間間隔(如5分鐘)勇蝙,如果沒有沫勿,只加載數(shù)據(jù)庫數(shù)據(jù),不需要再做網(wǎng)絡請求味混。當然产雹,還有一些隱式的http請求框架會緩存服務器數(shù)據(jù),在一定時間內(nèi)不再請求網(wǎng)絡翁锡,或者當服務器返回304時將之前緩存的數(shù)據(jù)直接返回蔓挖。

  3. 合并多個請求。現(xiàn)在有很多現(xiàn)成HTTP框架供我們使用馆衔,我們幾乎只用寫配置就可以搞定一個url請求瘟判,但是這里有很多需要服務端配合的,比如:json數(shù)據(jù)格式角溃,WebP代替jpg拷获,支持斷點續(xù)傳,多個請求合并成一個减细,盡量不做重定向匆瓜,服務器緩存以及負載均衡等。

  4. 控制請求并發(fā)量未蝌。對客戶端本身驮吱,除了上述的實現(xiàn),我們還需要合理的緩存萧吠,控制最大請求并發(fā)量左冬,及時取消已失效的請求,過濾重復請求怎憋,timeout時間設置又碌,請求優(yōu)先級設置等。

五绊袋、代碼規(guī)范

接著leo給大家 補充些代碼規(guī)范毕匀。

  • 你要知道for loop中不要聲明臨時變量,不到萬不得已不要在里面寫try catch癌别。

  • 明白垃圾回收機制皂岔,避免頻繁GC,內(nèi)存泄漏展姐,OOM躁垛。(有機會專門說)

  • 合理使用數(shù)據(jù)類型剖毯,比如StringBuilder代替String,(筆試題最常見的是str+=”str”中有幾個對象) 教馆,少用枚舉enum逊谋,少用父類聲明。(List,Map)

  • 如果你有頻繁的new線程土铺,那最好通過線程池去execute它們胶滋,減少線程創(chuàng)建開銷。

  • 你要知道單例的好處悲敷,并正確的使用它究恤。

  • 多用常量,少用顯式的”action_key”后德,并維護一個常量類部宿,別重復聲明這些常量。

  • 如果可以瓢湃,至少要弄懂設計模式中的策略模式理张,組合模式,裝飾模式绵患,工廠模式涯穷,觀察者模式,這些能幫助你合理的解耦藏雏,即使需求頻繁變更,你也不用害怕牽一發(fā)而動全身作煌。需求變更不可怕掘殴,可怕的是沒有在寫代碼之前做合理的設計。

優(yōu)化當然還有很多很多粟誓,leo所說的也只是一個大的輪廓奏寨,還是需要自己不斷的嘗試。會開發(fā)寫代碼跟會做產(chǎn)品的區(qū)別還是蠻大的鹰服,僅僅是態(tài)度就能刷死80%的碼農(nóng)了病瞳。當你碰到一些需要優(yōu)化的地方,耐心的去分析悲酷,時間的累積會讓你成為真正的工程師套菜。

另外優(yōu)化也沒有絕對的完美,每一次優(yōu)化都是基于當前的業(yè)務來做的设易,要明白溝通是最好的優(yōu)化逗柴,不盲從,不隨便顿肺,三思而后行戏溺。整理出來的渣蜗,以上就這些了,希望對你們有幫助旷祸,有什么問題耕拷,歡迎聯(lián)系,一起提高技術知識托享!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骚烧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嫌吠,更是在濱河造成了極大的恐慌止潘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辫诅,死亡現(xiàn)場離奇詭異凭戴,居然都是意外死亡,警方通過查閱死者的電腦和手機炕矮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門么夫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肤视,你說我怎么就攤上這事档痪。” “怎么了邢滑?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵腐螟,是天一觀的道長。 經(jīng)常有香客問我困后,道長乐纸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任摇予,我火速辦了婚禮汽绢,結果婚禮上,老公的妹妹穿的比我還像新娘侧戴。我一直安慰自己宁昭,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布酗宋。 她就那樣靜靜地躺著积仗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜕猫。 梳的紋絲不亂的頭發(fā)上斥扛,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音,去河邊找鬼稀颁。 笑死芬失,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的匾灶。 我是一名探鬼主播棱烂,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阶女!你這毒婦竟也來了颊糜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤秃踩,失蹤者是張志新(化名)和其女友劉穎衬鱼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體憔杨,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鸟赫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了消别。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抛蚤。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖寻狂,靈堂內(nèi)的尸體忽然破棺而出岁经,到底是詐尸還是另有隱情,我是刑警寧澤蛇券,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布缀壤,位于F島的核電站,受9級特大地震影響纠亚,放射性物質(zhì)發(fā)生泄漏诉位。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一菜枷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叁丧,春花似錦啤誊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稚瘾,卻和暖如春牡昆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工丢烘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柱宦,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓播瞳,卻偏偏與公主長得像掸刊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赢乓,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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