1.布局優(yōu)化
為什么?
Android系統(tǒng)每個(gè)16ms發(fā)出VSYNC信號(hào),觸發(fā)對(duì)UI的渲染,要想達(dá)到界面流暢,必須實(shí)現(xiàn)60fps,也就意味著大多數(shù)的操作必須在16ms完成.
除了上面界面過(guò)于復(fù)雜導(dǎo)致渲染不能及時(shí)完成之外,還存在過(guò)度繪制問(wèn)題.所謂過(guò)度繪制就是某個(gè)像素在同一幀的時(shí)間內(nèi)被繪制多次.在多層次的UI界面中,如果不可見(jiàn)的UI也在進(jìn)行繪制,那么這些重合區(qū)域的像素就會(huì)被繪制多次,從而浪費(fèi)大量的CPU和GPU資源.過(guò)度繪制也發(fā)生在背景重疊的情況下,比如Layout中有自己的背景,同時(shí)子View中又有自己的背景.
如何檢測(cè)?
使用HierarchyViewer來(lái)查找Activity中的布局是否過(guò)于復(fù)雜
在開(kāi)發(fā)者選項(xiàng)中打開(kāi)Show GPU Overdraw選項(xiàng)進(jìn)行觀(guān)察是否存在過(guò)度繪制
在開(kāi)發(fā)者選項(xiàng)中選擇Profile GPU Rendering,選中On screen as bar
使用TraceView來(lái)觀(guān)察CPU執(zhí)行情況
如何優(yōu)化?
減少布局的層級(jí),合理的使用include,merge,ViewStub
自定義組件的onDraw()中避免大量創(chuàng)建臨時(shí)對(duì)象,比如String,以免頻繁觸發(fā)GC
自定義組件的onDraw()中,考慮使用canvas.clipRect()繪制需要被繪制的區(qū)域
對(duì)像ListView這樣的組件容器,考慮使用convertView,使用ViewHolder,
考慮使用性能更高的組件,比如推薦使用RecycleView來(lái)代替ListView,使用staticlayout來(lái)實(shí)現(xiàn)自動(dòng)換行
2.內(nèi)存優(yōu)化
為什么?
資源總是有限的,內(nèi)存同樣也是一種資源.在A(yíng)ndroid當(dāng)中,過(guò)度的/不恰當(dāng)占用內(nèi)存資源,會(huì)導(dǎo)致應(yīng)用頻繁被殺死,最終也會(huì)影響用戶(hù)的整體體驗(yàn).任何一名開(kāi)發(fā)者,都應(yīng)該將節(jié)省內(nèi)存牢記心中.
如何檢測(cè)?
使用LeakCanary
使用MAT分析Java堆
使用Android Device Monitor中的Application Tracker追蹤內(nèi)存分配信息
Android Studio中的Android Monitor,選擇其中的Memory
如何優(yōu)化?
主動(dòng)的釋放內(nèi)存,在onLowMemory()和onTrimMemory()中適當(dāng)?shù)尼尫艃?nèi)存
避免內(nèi)存泄漏和內(nèi)存溢出
在使用Bitmap的時(shí)候,考慮對(duì)其進(jìn)行壓縮,使用緩存或者改變顏色模式,比如android默認(rèn)的顏色格式是ARGB_8888,在要求不高的情況下可以采用RGB__565,這樣每個(gè)像素占用的內(nèi)存就可懂4byte到2byte.
減少幀動(dòng)畫(huà)的使用,如果需要,通過(guò)SurfaceView實(shí)現(xiàn)
使用更輕量級(jí)的數(shù)據(jù)結(jié)構(gòu),比如ArrayMap/SparseArray
合理的使用相關(guān)組件,比如Service和Webview,在不需要的時(shí)候主動(dòng)結(jié)束其生命周期
合理的使用多進(jìn)程,比如像音樂(lè)播放器類(lèi),可以分為主進(jìn)程和播放進(jìn)程
使用異步隊(duì)列時(shí)考慮有界隊(duì)列
如果你能明確知道HashMap的大小,那就再初始化時(shí)為其制定容量
?
3.電量?jī)?yōu)化
為什么?
電量是移動(dòng)設(shè)備非常寶貴的資源,作為一名開(kāi)發(fā)者,有必要為用戶(hù)著想,減少電量的消耗.調(diào)查顯示通常只有30%左右的電量是被程序核心的功能所消耗,比如界面渲染,剩下的70%則是被上報(bào)數(shù)據(jù),位置更新,后臺(tái)通知所消耗.
如何檢測(cè)?
手機(jī)選項(xiàng)中通過(guò)查看APP的電量消耗的統(tǒng)計(jì)數(shù)據(jù)
使用Battery Historian Tool來(lái)查看詳細(xì)的電量消耗
如何優(yōu)化?
減少喚醒屏幕的次數(shù)與持續(xù)的時(shí)間,正確的使用WakeLock.
延遲非必須的操作到充電狀態(tài)時(shí),比如日志上報(bào)完全可以在夜間充電時(shí)完成,這點(diǎn)可以結(jié)合JobScheduler使用
使用傳感器采集數(shù)據(jù)時(shí),一旦不需要記得取消注冊(cè).
減少網(wǎng)絡(luò)通信,合并通信.
合理使用定位功能,減少位置更新頻率以及根據(jù)實(shí)際情況使用不同精度的定位需求
4.網(wǎng)絡(luò)優(yōu)化
為什么?
現(xiàn)在A(yíng)pp幾乎都需要聯(lián)網(wǎng)操作,做好網(wǎng)絡(luò)優(yōu)化一方面可以提高體驗(yàn),另一方面可以減少流量和電量的損耗.另外,無(wú)論是對(duì)用戶(hù)還是網(wǎng)絡(luò)服務(wù)提供者,網(wǎng)絡(luò)同樣是一種資源,任何開(kāi)發(fā)者都不應(yīng)該假設(shè)網(wǎng)絡(luò)資源是無(wú)限制的.
如何檢測(cè)?
使用Android Studio里的Network Traffic Tools來(lái)查看網(wǎng)絡(luò)請(qǐng)求
使用Android Studio中的Monitor
使用Fidder或者Charles等抓包工具分析網(wǎng)絡(luò)數(shù)據(jù)包
如何優(yōu)化?
有必要的時(shí)候務(wù)必做好緩存,無(wú)論是圖片還是普通的數(shù)據(jù),使用LruCache和DiskLruCache構(gòu)建自己的緩存系統(tǒng),并根據(jù)實(shí)際場(chǎng)景設(shè)計(jì)緩存策略
避免過(guò)度的網(wǎng)絡(luò)同步,合并相關(guān)的網(wǎng)絡(luò)請(qǐng)求
根據(jù)實(shí)際場(chǎng)景確定請(qǐng)求策略,避免使用固定的間隔頻率來(lái)進(jìn)行網(wǎng)絡(luò)操作.比如連接WiFi并充電的情況下請(qǐng)求頻率可以高,第一次網(wǎng)絡(luò)請(qǐng)求失敗后可以使用雙倍的時(shí)間間隔來(lái)進(jìn)行下一次
減少數(shù)據(jù)傳輸量,對(duì)傳輸?shù)臄?shù)據(jù)做壓縮.如果傳輸?shù)氖菆D片,需要選擇合適的圖片格式以及根據(jù)顯示大小請(qǐng)求合適規(guī)格的圖片.對(duì)于普通數(shù)據(jù),可以考慮使用ProtocalBuffers來(lái)減小傳輸數(shù)據(jù)的大小.
某些情況下可以采用IP直連,一方面可以減少DNS解析時(shí)間,另一方面可以防止域名劫持
5.啟動(dòng)優(yōu)化
為什么?
啟動(dòng)優(yōu)化看起來(lái)并不是那么必要,但從心理學(xué)角度而言,越快的啟動(dòng)速度往往給用戶(hù)以性能好,高效可靠的心理暗示,這就很容易讓用戶(hù)對(duì)其產(chǎn)生好感,為你后面打動(dòng)用戶(hù)留下了余地.
如何檢測(cè)?
使用Method Tracing
使用Systrace,比如在onCreate中添加trace.beginSection()和trace.endSection()
使用adb shell am start -W [packageName]/[packageName.MainActivity]
測(cè)量冷啟動(dòng)時(shí)間
如何優(yōu)化?
Activity的onCreate()中減少?gòu)?fù)雜和耗時(shí)的操作
Application的onCreate(),attachBaseContext()中同樣減少?gòu)?fù)雜和耗時(shí)的操作,但是對(duì)于很多App在此處會(huì)執(zhí)行大量組件和服務(wù)的初始化操作,如果可能考慮并行初始化
提供自定義啟動(dòng)窗口,比如將一張圖片通過(guò)設(shè)置主題的方式顯示為啟動(dòng)窗口.
優(yōu)化布局
6.體積優(yōu)化
為什么?
對(duì)用戶(hù)而言,無(wú)論是用戶(hù)空間還是網(wǎng)絡(luò),亦或是時(shí)間,都是資源.體積優(yōu)化就是為用戶(hù)節(jié)省資源的重要一環(huán).如果你現(xiàn)在做的是SDK類(lèi)產(chǎn)品,那么體積優(yōu)化同樣重要.
如何檢測(cè)?
使用Android Lint檢查沒(méi)有使用的資源
如何優(yōu)化?
減少不必要的依賴(lài)庫(kù)/Jar,在滿(mǎn)足需求的前提下優(yōu)先選擇體積小的.
使用Proguard工具進(jìn)行代碼瘦身,優(yōu)化,混淆
減少so文件的數(shù)量,根據(jù)實(shí)際情況提供so文件
使用Gradle中的shrinkResource來(lái)將無(wú)用的代碼和資源排除在A(yíng)PK安裝包之外
減少圖片資源的大小,考慮圖片壓縮或者使用Vertor Drawable替代png/jpeg
有選擇的提供對(duì)應(yīng)分辨率的圖片資源
復(fù)用已經(jīng)存在的圖片,多用通過(guò)代碼對(duì)已有圖片進(jìn)行變換的方式實(shí)現(xiàn)復(fù)用
使用插件化技術(shù)(如果項(xiàng)目簡(jiǎn)單就不要使用)
7.性能優(yōu)化
能發(fā)揮出100%的能力就不要只發(fā)揮其中的50%,這對(duì)應(yīng)用而言并非壞事.同樣的價(jià)格賣(mài)給用戶(hù)兩輛車(chē),我想大多數(shù)人會(huì)選擇性能更好的.
如何檢測(cè)?
使用Lint執(zhí)行靜態(tài)分析,在A(yíng)ndroid Studio的Analysis->Inspect Code
在開(kāi)發(fā)者選項(xiàng)中開(kāi)啟StrictMode或者在代碼中開(kāi)啟
代碼Review
如何優(yōu)化?
任務(wù)并行化,對(duì)可能的任務(wù)進(jìn)行并行操作,多借助線(xiàn)程池而非直接使用線(xiàn)程
如何需要序列化數(shù)據(jù),優(yōu)先考慮Android自身提供的而非Java提供的Serializable
選擇合適的數(shù)據(jù)結(jié)構(gòu),明確List/Set/Map/Stack操作的復(fù)雜度
使用Android提供更高效的容器,比如使用ArrayMap來(lái)代替HashMap,此外還是有SparseBoolMap,SparseIntMap,SparseLongMap
使用靜態(tài)常量代替Enum類(lèi)型,可以減少至少兩倍的內(nèi)存消耗
使用對(duì)象池技術(shù),比如提供想String一樣的對(duì)象池
使用緩存技術(shù)
字符串拼接操作有限使用StringBuilder
對(duì)相關(guān)的算法和邏輯進(jìn)行優(yōu)化,減少不必要的流程
采用JNI,對(duì)計(jì)算量較大的邏輯將其協(xié)程so文件,如圖片處理
業(yè)務(wù)優(yōu)化
除了上述比較通用的優(yōu)化方案之外,也應(yīng)該花點(diǎn)時(shí)間放在業(yè)務(wù)優(yōu)化上.很多時(shí)候,迫于時(shí)間壓迫,當(dāng)前實(shí)現(xiàn)業(yè)務(wù)的方案并非最優(yōu).比如為了支持多張圖片上傳,很多人直接使用串行操作,盡管這樣做容易實(shí)現(xiàn),但是卻并非最佳.
由于每個(gè)產(chǎn)品的業(yè)務(wù)并不相同,也就很難有通用的優(yōu)化方案,這里又兩個(gè)目標(biāo)值得思考:
如果有可能,串行業(yè)務(wù)并行化
如果有可能,簡(jiǎn)化業(yè)務(wù)流程.將一大象關(guān)進(jìn)冰箱的方法就是打開(kāi)冰箱,將大象放進(jìn)去,最后關(guān)閉冰箱.
之所以把業(yè)務(wù)優(yōu)化放在最后的根本原因是業(yè)務(wù)優(yōu)化的風(fēng)險(xiǎn)較高,需要團(tuán)隊(duì)的整體配合來(lái)完成.
Android中圖片有四種顏色格式
默認(rèn)的是ARGB_8888,其中ARGB分別代表的是透明度,紅色,綠色,藍(lán)色,每個(gè)值分別用8位來(lái)記錄,也就是一個(gè)像素會(huì)占用4byte,共32位.
而ARGB_4444和以上很類(lèi)似,但是每個(gè)值分別用4位來(lái)記錄,也就是一個(gè)像素會(huì)占用2byte,共16位.
RGB_565則分別用5位,6位,5位來(lái)記錄每個(gè)值,不存在透明度,每個(gè)像素會(huì)占用2byte,共16位.
ALPHA_8:該像素只保存透明度,會(huì)占用1byte,共8位.
在實(shí)際應(yīng)用中而言,值推薦使用ARGB_8888以及RGB_565,如果你不需要透明度,那么就選擇RGB_565,可以減少一半的內(nèi)存占用