App性能優(yōu)化淺談

前言

前段時間給公司的小伙伴們進(jìn)行了關(guān)于app性能優(yōu)化的技術(shù)分享溯壶,這里我稍微整理一下也給大家分享一下及皂,關(guān)于性能優(yōu)化這個話題很大甫男,涉及面可以很廣,也可以很深入验烧,本人能力有限板驳,不會給大家講特別難懂,特別底層的東西碍拆,都是我們開發(fā)能著手去做的點若治,大家都在講性能優(yōu)化,但對于項目經(jīng)驗不夠豐富的朋友很難有一個概念感混,做優(yōu)化的時候也會比較茫然端幼,這里我就給大家指明方向。

從何講起弧满?

筆者在做產(chǎn)品開發(fā)的時候婆跑,也遇到性能瓶頸,測試工程師反饋了一些比較明顯的問題庭呜,比如UI界面的過度繪制滑进,列表滑動有明顯卡頓,比較耗內(nèi)存等等募谎,但以往的都沒有針對性的去做相應(yīng)的優(yōu)化扶关,所以借著保證產(chǎn)品質(zhì)量的出發(fā)點,自己定了相關(guān)的性能優(yōu)化方案数冬,可能不太成熟节槐,不過可以逐步完善,并找到最適合自己產(chǎn)品的優(yōu)化方案吉执。

這里我定了四個方向:

  • 響應(yīng)時間(Response Time)
  • 界面卡頓(ANR)
  • 耗內(nèi)存(Memory)
  • 內(nèi)存泄露(Out of memory)

響應(yīng)時間

這里指的是客戶端與服務(wù)端交互,拿到數(shù)據(jù)地来、解析戳玫、再到顯示到界面整個過程耗費(fèi)的時間。

這個部分涉及客戶端的優(yōu)化未斑,也涉及服務(wù)端的優(yōu)化咕宿,這里只討論客戶端。

HTTP請求方式

我們的app一般離不開網(wǎng)絡(luò)蜡秽,請求接口是最平常的操作了府阀,如何請求,請求什么我們在開發(fā)初期就要定好芽突,服務(wù)端給我的提供的接口试浙,大致可以通過GET、POST寞蚌、HEAD田巴、PUT钠糊、DELETE這幾種請求方式,不同的請求方式有不同應(yīng)用場景壹哺,比如GET請求抄伍,應(yīng)當(dāng)用來請求返回結(jié)果,參數(shù)是作為url的一部分管宵;POST請求截珍,用于請求會更改服務(wù)端數(shù)據(jù)或狀態(tài);HEAD請求跟GET一樣箩朴,只是服務(wù)器不能在響應(yīng)里返回消息主體岗喉;PUT請求,用于將網(wǎng)頁放置正確的地方隧饼;DELETE請求用于刪除服務(wù)器指定文檔沈堡。

使用優(yōu)秀的開源Http框架是我們比較好的選擇,它的優(yōu)點是經(jīng)過市場的驗證燕雁,很多坑都被填過诞丽,缺點也是我們需要去深究它才能對其進(jìn)行擴(kuò)展,遇到坑也不一定能填拐格。

如果自己造輪子的話僧免,還需要我們花時間去驗證去適應(yīng)我們的業(yè)務(wù)需求,但好處是我們可以自己去擴(kuò)展可把控捏浊,不過這很考量開發(fā)者的素質(zhì)懂衩。

數(shù)據(jù)解析

實際開發(fā)當(dāng)中服務(wù)端的返回數(shù)據(jù)格式無非就兩種:

  • JSON
  • XML

這兩種格式數(shù)據(jù)格式各有優(yōu)劣,從可讀性來看金踪,xml略微好一點浊洞,不過JSON也有規(guī)范的標(biāo)簽,從解析難度和速度來看胡岔,大家都比較傾向使用JSON法希,目前JSON也是主流的數(shù)據(jù)格式。

在Android中均可以使用優(yōu)秀的解析庫來加快我們的解析速度靶瘸,XML中有dom4j苫亦,JSON有Jackson、Gson怨咪,我們通過這些庫實現(xiàn)我們更快的完成數(shù)據(jù)解析屋剑,提高我們的開發(fā)效率。

數(shù)據(jù)存儲

上一節(jié)講的是數(shù)據(jù)解析诗眨,我們解析完后的數(shù)據(jù)唉匾,可能就需要將數(shù)據(jù)存儲在某個地方,Android的五種存儲方式:

  • Content Provider(主要用來向其他應(yīng)用程序共享數(shù)據(jù))
  • SQLite(存儲數(shù)據(jù)到數(shù)據(jù)庫中)
  • File(本地文件保存)
  • SharedPreference(主要用來保存簡單的配置信息)
  • 網(wǎng)絡(luò)存儲(WebService返回的數(shù)據(jù)或是解析HTTP協(xié)議實現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)交互)

為了提高應(yīng)用程序的響應(yīng)時間匠楚,數(shù)據(jù)緩存是一個比較好的方式肄鸽,我們可以預(yù)處理服務(wù)器返回的數(shù)據(jù)卫病,對數(shù)據(jù)進(jìn)行緩存刷新。

優(yōu)化點:

  • 異步請求網(wǎng)絡(luò)數(shù)據(jù)
  • 預(yù)處理服務(wù)器返回數(shù)據(jù)
  • 異步進(jìn)行數(shù)據(jù)存儲操作
  • 數(shù)據(jù)緩存刷新
  • Timeout超時重試
  • 在主線程中操作UI

界面卡頓

ANR表示"應(yīng)用程序無響應(yīng)"典徘,這個是需要我們避免發(fā)生的事情蟀苛,出現(xiàn)這個異常的原因:

  • 主線程 (“事件處理線程” / “UI線程”) 在5秒內(nèi)沒有響應(yīng)輸入事件
  • BroadcastReceiver在10秒內(nèi)沒有執(zhí)行完畢

導(dǎo)致ANR的原因有很多,一般情況就是在UI線程做了耗時的操作逮诲,例如"網(wǎng)絡(luò)請求"帜平、數(shù)據(jù)庫操作。

那么如何避免梅鹦?

  • UI線程只做界面刷新裆甩,不做任何耗時操作,耗時操作放在子線程來做
  • 可以使用Thread+handle或者AsyncTask來進(jìn)行邏輯處理

耗內(nèi)存

每部手機(jī)的內(nèi)存有限齐唆,我們這里所說的內(nèi)存指的是手機(jī)的RAM嗤栓,它是Ramdom Access Memory的縮寫,我們應(yīng)用程序的需要隨機(jī)讀寫的數(shù)據(jù)就存在RAM中箍邮,Android手機(jī)之所以會比較耗內(nèi)存茉帅,這跟Android后臺的處理有關(guān),我們知道Android應(yīng)用是使用Java開發(fā)的锭弊,運(yùn)行Java需要有虛擬機(jī)堪澎,說明每開啟一個應(yīng)用都會創(chuàng)建一個虛擬機(jī),而這是需要內(nèi)存的味滞,所以我們開的應(yīng)用越多樱蛤,后臺進(jìn)程越多,內(nèi)存都分配出去了剑鞍,才導(dǎo)致內(nèi)存消耗的嚴(yán)重昨凡。

其實這個問題我們是沒得破的,只要內(nèi)存不夠蚁署,我們的應(yīng)用還是會卡便脊。我們開發(fā)的應(yīng)用依賴與系統(tǒng)給我們分配的堆內(nèi)存,一般上限在16M~48M形用,但我們可以通過在AndroidManifest設(shè)置Application屬性largeHeap=“true”來申請更多的堆內(nèi)存就轧。

通過以下代碼獲取可用堆內(nèi)存限制:

mActivityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
 mMaxMemory = mActivityManager.getMemoryClass();

內(nèi)存泄露

內(nèi)存泄露這個問題已經(jīng)被說爛了证杭,大家都知道有內(nèi)存泄露這個問題存在田度,但為什么會發(fā)生內(nèi)存泄露?

這里的內(nèi)存泄露并不是真正意思上的泄露解愤,而是因為內(nèi)存不足不能進(jìn)行GC操作镇饺,從而導(dǎo)致占用內(nèi)存過大,拋出out of memory異常送讲,而被系統(tǒng)Kill掉奸笤。

JVM回收機(jī)制

是時候講講JVM的回收機(jī)制了惋啃,看下圖:

JVM分代

JVM對Java對象分了三個代進(jìn)行管理,分別為年輕代监右、年老代边灭、永久代。
年輕代(Young Generation):絕大多數(shù)的Java對象會在年輕代被分配健盒,也會在年輕代被回收绒瘦。
年老代(Old Generation):在年輕代長期存在沒有被回收的Java對象會轉(zhuǎn)移到年老代,這個堆空間通常會被比年輕代的堆空間要大扣癣。
永久代:存放VM和Java類的元數(shù)據(jù)惰帽,以及interned字符串和類的靜態(tài)變量。

這里涉及到JVM的相關(guān)知識父虑,這里不繼續(xù)深入探討该酗。

但我們應(yīng)該可以知道垃圾回收器的作用:

  • 分配內(nèi)存
  • 保證所有正在被引用的對象還存在于內(nèi)存中
  • 回收執(zhí)行代碼已經(jīng)不再引用的對象所占的內(nèi)存

對象引用

Java的引用類型可以分為以下幾種:

  • 強(qiáng)引用(Strong Ref):強(qiáng)可達(dá),去掉強(qiáng)可達(dá)士嚎,才會被回收呜魄。
  • 軟引用(Soft Ref):內(nèi)存夠用,就保持航邢,內(nèi)存吃緊耕赘,則回收,主要用來做緩存膳殷。
  • 弱引用(Weak Ref):比Soft Ref弱操骡,即使內(nèi)存不吃緊也會被回收。
  • 虛引用(Phantom Ref):不會在內(nèi)存保持任何對象赚窃。

一圖勝千言:

對象引用

利用Strong Ref册招,存儲大量數(shù)據(jù),直到heap撐破勒极,利用inter strings(或者class loader加載大量的類)把perm gen撐破是掰,然后就是內(nèi)存泄露了。

如何優(yōu)化辱匿?

前面講了一些背景知識键痛,對我們理解內(nèi)存優(yōu)化有一定的幫助,下面就簡單說一下我們優(yōu)化的方向:

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

布局優(yōu)化

大家可以拿出你們的Android機(jī)
開發(fā)者工具-Profile GPU Rendering-選擇在屏幕上顯示條形圖

-藍(lán)色代表測量繪制Display List的時間
-紅色代表OpenGL渲染Display List所需要的時間
-黃色代表CPU等待GPU處理的時間
-中間綠色橫線代表VSYNC時間16ms匾七,盡量將所有條形圖控制在這條綠線下

為什么是16ms絮短?

Android 通知界面渲染和重繪的時間要在16ms內(nèi)完成,如果超過16ms昨忆,就會導(dǎo)致丟幀丁频,也就是我們常說的卡頓。

優(yōu)化點:

  • 避免OverDraw
  • 優(yōu)化布局層級
  • 避免過多無用嵌套
    • 使用<include>標(biāo)簽重用layout
    • 使用<ViewStub>延遲加載
  • Hierarchy View進(jìn)行層級分析

具體的使用方法,這里不介紹了席里,不懂就百度叔磷。

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

內(nèi)存優(yōu)化的點有很多,這里我主要分為兩大塊:

  • Bitmap優(yōu)化
  • 代碼優(yōu)化

Bitmap優(yōu)化

  1. 使用適當(dāng)分辨率和大小的圖片
  2. 及時回收內(nèi)存(bitmap.recycle())
  3. 使用圖片緩存(LruCache和DiskLruCache)

第一點奖磁,就是按需顯示改基,比如列表中的圖片,你可以顯示縮略圖咖为,詳情頁寥裂,你就可以加載相應(yīng)的分辨率的圖片,這樣可以減少內(nèi)存消耗案疲,一般可以要求服務(wù)端提供多種分辨率的圖片封恰。

第二點,Bitmap是很耗內(nèi)存褐啡,尤其是加載比較大的bitmap诺舔,可以想到的優(yōu)化方案就是使用記得回收,對Bitmap進(jìn)行壓縮备畦,使用BitmapFactory.Options設(shè)置inSampleSize就可以縮小圖片低飒。

第三點,圖像緩存懂盐,這個可以利用成熟的圖片加載框架褥赊,比如Universal-ImageLoader、Fresco莉恼、Picasso拌喉,這些框架都對圖片進(jìn)行了很好的優(yōu)化,大家可以對比一下俐银,選擇使用即可尿背。

代碼優(yōu)化

關(guān)于代碼這個就有的說了,任何能改進(jìn)我們程序的優(yōu)化點都能寫在這里捶惜,這里沒辦法把所有優(yōu)化的點列在這里田藐,只提供相關(guān)的參考,剩下的就好各位經(jīng)驗總結(jié)和積累了吱七。

優(yōu)化點:

  • 對常量使用static修飾符
  • 使用靜態(tài)方法
  • 減少不必要的成員變量
  • 盡量不要使用枚舉汽久,少用迭代器
  • 對Cursor、Receiver踊餐、Sensor景醇、File等對象,要注意它們的創(chuàng)建市袖、回收與注冊啡直、反注冊
  • 避免大量使用注解、反射
  • 使用RenderScript苍碟、OpenGL來進(jìn)行復(fù)雜的繪圖操作
  • 使用SurfaceView來替代View進(jìn)行大量酒觅、頻繁的繪圖操作
  • 盡量使用視圖緩存,而不是每次都執(zhí)行inflate()方法解析視圖

注:這里引用了Android群英傳的相關(guān)優(yōu)化點

  • 創(chuàng)建新的對象都需要額外的內(nèi)存空間微峰,要盡量減少創(chuàng)建新的對象舷丹。
  • 將類、變量蜓肆、方法等等的可見性修改為最小颜凯。
  • 針對字符串的拼接,使用StringBuffer替代String仗扬。
  • 不要在循環(huán)當(dāng)中聲明臨時變量症概,不要在循環(huán)中捕獲異常。
  • 如果對于線程安全沒有要求早芭,盡量使用線程不安全的集合對象彼城。
  • 使用集合對象,如果事先知道其大小退个,則可以在構(gòu)造方法中設(shè)置初始大小募壕。
  • 文件讀取操作需要使用緩存類,及時關(guān)閉文件语盈。
  • 慎用異常舱馅,使用異常會導(dǎo)致性能降低。
  • 如果程序會頻繁創(chuàng)建線程刀荒,則可以考慮使用線程池代嗤。

以上都是些經(jīng)驗總結(jié),大致都相差無幾缠借,朋友們在做代碼優(yōu)化的時候资溃,可以根據(jù)這些優(yōu)化點,有針對性去重構(gòu)代碼烈炭,其實最重要還是代碼的可讀性溶锭,結(jié)構(gòu)清晰。

性能優(yōu)化工具

  • Memory Monitor - 內(nèi)存監(jiān)視工具
  • TraceView
  • MAT

Android開發(fā)者對與以上幾個性能調(diào)優(yōu)的工具一定不陌生符隙,這里我也不再寫那么多廢話了趴捅,關(guān)于它們的使用方法,官網(wǎng)還有一些大牛的博客都有介紹霹疫。

最后

寫這篇文章的出發(fā)點也是對Android性能優(yōu)化有個比較清楚的認(rèn)識拱绑,任何事情都不可能一蹴而就,需要循循漸進(jìn)丽蝎,對一個初學(xué)者你談優(yōu)化很不現(xiàn)實猎拨,我們先把基本的做好膀藐,再去考慮相應(yīng)的優(yōu)化,筆者也在不斷學(xué)習(xí)當(dāng)中红省,借鑒別人好的優(yōu)化方案额各,提高產(chǎn)品的質(zhì)量,感謝大家對筆者的關(guān)注吧恃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虾啦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痕寓,更是在濱河造成了極大的恐慌傲醉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呻率,死亡現(xiàn)場離奇詭異硬毕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)礼仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門昭殉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人藐守,你說我怎么就攤上這事挪丢。” “怎么了卢厂?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵乾蓬,是天一觀的道長。 經(jīng)常有香客問我慎恒,道長任内,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任融柬,我火速辦了婚禮死嗦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粒氧。我一直安慰自己越除,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布外盯。 她就那樣靜靜地躺著摘盆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饱苟。 梳的紋絲不亂的頭發(fā)上孩擂,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音箱熬,去河邊找鬼类垦。 笑死狈邑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚤认。 我是一名探鬼主播米苹,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烙懦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赤炒,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤氯析,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后莺褒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掩缓,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年遵岩,在試婚紗的時候發(fā)現(xiàn)自己被綠了你辣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡尘执,死狀恐怖舍哄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情誊锭,我是刑警寧澤表悬,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站益缎,受9級特大地震影響驶臊,放射性物質(zhì)發(fā)生泄漏葛躏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一饭庞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熬荆,春花似錦舟山、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纬黎,卻和暖如春幅骄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背本今。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工拆座, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留主巍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓挪凑,卻偏偏與公主長得像孕索,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子躏碳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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