優(yōu)化角度
RAM方面
- 內(nèi)存泄露優(yōu)化
- 避免OOM
- APP啟動(dòng)優(yōu)化
- 線程優(yōu)化
Res方面
- apk瘦身
- 布局優(yōu)化
- 繪制優(yōu)化
- ListView和Bitmap優(yōu)化
其他
- ANR分析
- 電量優(yōu)化
- 性能優(yōu)化工具
內(nèi)存泄露優(yōu)化
- 單例模式的持有;
- 靜態(tài)對(duì)象的持有
- 屬性動(dòng)畫不被cancel呆细,其持有view型宝,view又持有activity導(dǎo)致內(nèi)存泄露。
- 非靜態(tài)內(nèi)部類會(huì)持有外部類的引用絮爷,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的趴酣,或者在執(zhí)行耗時(shí)操作,就會(huì)長期的維持著外部類的引用
- 以匿名內(nèi)部類構(gòu)建的AsyncTask和新線程會(huì)隱式地帶有一個(gè)對(duì)外的引用坑夯,如果在activity結(jié)束時(shí)候沒有執(zhí)行完成岖寞,會(huì)造成內(nèi)存泄露,建議使用靜態(tài)內(nèi)部類柜蜈,在Activity銷毀時(shí)候也應(yīng)該取消相應(yīng)的任務(wù)AsyncTask::cancel()仗谆,避免任務(wù)在后臺(tái)執(zhí)行浪費(fèi)資源
- Context導(dǎo)致內(nèi)存泄漏
根據(jù)場景確定使用Activity的Context還是Application的Context,因?yàn)槎呱芷诓煌瑢?duì)于不必須使用Activity的Context的場景(Dialog),一律采用Application的Context,單例模式是最常見的發(fā)生此泄漏的場景淑履,比如傳入一個(gè)Activity的Context被靜態(tài)類引用隶垮,導(dǎo)致無法回收 - 靜態(tài)View導(dǎo)致泄漏
使用靜態(tài)View可以避免每次啟動(dòng)Activity都去讀取并渲染View,但是靜態(tài)View會(huì)持有Activity的引用秘噪,導(dǎo)致無法回收狸吞,解決辦法是在Activity銷毀的時(shí)候?qū)㈧o態(tài)View設(shè)置為null(View一旦被加載到界面中將會(huì)持有一個(gè)Context對(duì)象的引用,在這個(gè)例子中,這個(gè)context對(duì)象是我們的Activity蹋偏,聲明一個(gè)靜態(tài)變量引用這個(gè)View便斥,也就引用了activity) - BraodcastReceiver,ContentObserver威始,F(xiàn)ile椭住,Cursor,Stream字逗,Bitmap、系統(tǒng)服務(wù)等資源及時(shí)關(guān)閉宅广,它們內(nèi)部往往都使用了緩沖葫掉,會(huì)造成內(nèi)存泄漏,一定要確保關(guān)閉它并將引用置為null
- WebView導(dǎo)致的內(nèi)存泄漏
WebView只要使用一次跟狱,內(nèi)存就不會(huì)被釋放俭厚,所以WebView都存在內(nèi)存泄漏的問題,通常的解決辦法是為WebView單開一個(gè)進(jìn)程驶臊,使用AIDL進(jìn)行通信挪挤,根據(jù)業(yè)務(wù)需求在合適的時(shí)機(jī)釋放掉 - 集合中的對(duì)象未清理
集合用于保存對(duì)象,如果集合越來越大关翎,不進(jìn)行合理的清理扛门,尤其是入股集合是靜態(tài)的 - Bitmap導(dǎo)致內(nèi)存泄漏
bitmap是比較占內(nèi)存的,所以一定要在不使用的時(shí)候及時(shí)進(jìn)行清理纵寝,避免靜態(tài)變量持有大的bitmap對(duì)象 - 監(jiān)聽器未關(guān)閉
很多需要register和unregister的系統(tǒng)服務(wù)要在合適的時(shí)候進(jìn)行unregister,手動(dòng)添加的listener也需要及時(shí)移除
減少OOM
Android系統(tǒng)為每一個(gè)應(yīng)用程序都設(shè)置了一個(gè)硬性的Dalvik Heap Size最大限制閾值论寨,這個(gè)閾值在不同的設(shè)備上會(huì)因?yàn)镽AM大小不同而各有差異。ActivityManager.getMemoryClass()可以用來查詢當(dāng)前應(yīng)用的Heap Size閾值爽茴。命令行也可以查看相關(guān)的內(nèi)存信息
減少OOM方面:
其實(shí)避免內(nèi)存泄露也是間接避免了OOM
- 減少內(nèi)存分配量
- ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)葬凳,通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來記錄Mapping操作室奏。另外火焰,SparseArray更加高效在于他們避免了對(duì)key與value的autobox自動(dòng)裝箱,并且避免了裝箱后的解箱胧沫。
- 避免在Android里面使用Enum
- Android內(nèi)置字符串/顏色/圖片/動(dòng)畫/樣式以及簡單布局的使用昌简,可以在程序中直接飲用系統(tǒng)資源,減少apk體積琳袄,但要注意版本差異
APP啟動(dòng)優(yōu)化
一般情況下我們會(huì)利用主題去防止出現(xiàn)白屏
需要盡可能減少Application的onCreate中所要做的事情江场,比如一些不重要的SDK延遲或者異步加載;
有幾個(gè)方向:
1窖逗、利用開啟APP時(shí)候提前展示的window址否,快速展示一個(gè)界面,給用戶視覺上快速的感覺:onCreate函數(shù)開頭將activity的theme設(shè)置為style中的主題,然后在oncreate函數(shù)運(yùn)行過程中又切換成activity標(biāo)簽下配置的背景佑附。
2樊诺、異步初始化三方組件
3、減少IO音同、網(wǎng)絡(luò)等密集請(qǐng)求
線程優(yōu)化
采用線程池词爬,一是減少線程重復(fù)創(chuàng)建或銷毀帶來的性能損耗;
二是控制最大并發(fā)線程數(shù)权均,防止大量線程搶CPU造成卡頓
apk瘦身
為什么要瘦身:大體積下載轉(zhuǎn)化率低顿膨,同時(shí)對(duì)服務(wù)器增加流量壓力,此外會(huì)影響手機(jī)廠商預(yù)置應(yīng)用
利用ProGuard壓縮代碼去除無用資源叽赊,通過移除不需要的代碼恋沃,重命名類,域與方法等等對(duì)代碼進(jìn)行壓縮必指,優(yōu)化與混淆囊咏。使用ProGuard可以使得你的代碼更加緊湊,這樣能夠減少mapping代碼所需要的內(nèi)存空間塔橡。
使用 XZ 或者 7-Zip 壓縮Library
第三方開源庫的瘦身梅割,僅保留自己需要的部分
so的優(yōu)化與配置,只保留一類so
動(dòng)態(tài)下發(fā)一些資源:字庫葛家、so户辞、換膚包等
布局優(yōu)化
盡量減少布局層級(jí),同層級(jí)時(shí)候使用功能較低的ViewGroup惦银,比如FrameLayout和LinearLayout咆课,但性能較低的layout拓展性差難以實(shí)現(xiàn)較復(fù)雜的布局,導(dǎo)致需要嵌套扯俱,這時(shí)候還是建議使用RelativeLayout畢竟嵌套也會(huì)降低性能书蚪。
實(shí)用策略:
- inlcude標(biāo)簽 便于布局重用
- merge標(biāo)簽 和include配合使用,在被include的布局根元素替換為merge標(biāo)簽迅栅,能夠減少布局層級(jí)
- ViewStub實(shí)現(xiàn)需要時(shí)加載布局殊校,setVisibility或者inflate之后,被內(nèi)部引用布局替換掉读存,提高應(yīng)用啟動(dòng)性能为流。
繪制優(yōu)化
為了讓屏幕的刷新幀率達(dá)到60fps,我們需要確保在時(shí)間16ms(1000/60Hz)內(nèi)完成單次刷新的操作(包括measure让簿、layout以及draw)
onDraw方法中不要?jiǎng)?chuàng)造大量臨時(shí)對(duì)象敬察,因?yàn)樵摲椒〞?huì)被頻繁調(diào)用,大量GC傷不起尔当。此外也不要使用耗時(shí)操作你懂的啦
減少overDraw的產(chǎn)生莲祸,盡量讓一個(gè)像素只繪制一次,減少布局重疊。
除了布局精簡锐帜,還可以去掉每行RelativeLayout的背景色田盈;去掉每行TextView的背景色;必要的話去掉activity使用的Theme的背景色缴阎。
ListView優(yōu)化
ListView只是一個(gè)代表允瞧,很多復(fù)雜的View都可以參考如下建議
使用ViewHolder并減少在getView中的復(fù)雜操作
根據(jù)滑動(dòng)速度來變化view的操作,比如快速滑動(dòng)時(shí)候不開啟線程
采用硬件加速來優(yōu)化view的繪制
Bitmap優(yōu)化
- 采用BitmapFactory來對(duì)圖片進(jìn)行采樣
inSampleSize:縮放比例蛮拔,在把圖片載入內(nèi)存之前述暂,我們需要先計(jì)算出一個(gè)合適的縮放比例,避免不必要的大圖載入建炫。
decode format:解碼格式贸典,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異踱卵。 - 使用更小的圖片
盡量使用更小的圖片不僅僅可以減少內(nèi)存的使用,還可以避免出現(xiàn)大量的InflationException据过。假設(shè)有一張很大的圖片被XML文件直接引用惋砂,很有可能在初始化視圖的時(shí)候就會(huì)因?yàn)閮?nèi)存不足而發(fā)生InflationException,這個(gè)問題的根本原因其實(shí)是發(fā)生了OOM绳锅。 - 實(shí)現(xiàn)對(duì)象的復(fù)用
LRU緩存
ANR分析
避免ANR的核心西路是不要在主線程做耗時(shí)操作西饵,ANR在activity中的規(guī)定出現(xiàn)時(shí)限是5秒,在廣播中是10秒
出現(xiàn)原因有主線程無法響應(yīng)觸摸或者用戶輸入鳞芙,線程之間等待死鎖等等眷柔。
電量優(yōu)化
為了減少電量的消耗,在蜂窩移動(dòng)網(wǎng)絡(luò)下原朝,最好做到批量執(zhí)行網(wǎng)絡(luò)請(qǐng)求驯嘱,盡量避免頻繁的間隔網(wǎng)絡(luò)請(qǐng)求
合理的使用一些傳感器、謹(jǐn)慎的使用Wake Lock
檢測可以利用battery-historian
其他建議
減少對(duì)象
減少枚舉
常量使用static final修飾
使用Android特有的數(shù)據(jù)結(jié)構(gòu)喳坠,如SparseArray和pair他們具備更好的性能
適當(dāng)使用弱引用和軟引用
采用內(nèi)存緩存和磁盤緩存
盡量使用靜態(tài)內(nèi)部類
性能優(yōu)化工具
Android Device Monitor(DDMS) was deprecated in Android Studio 3.1 and removed from Android Studio 3.2,此外鞠评,SYSTrace TraceView都被AndroidProfile取代了,不過特定場景上述工具還可用
性能分析工具分兩個(gè)流派:
第一個(gè)流派是 instrument壕鹉。獲取一段時(shí)間內(nèi)所有函數(shù)的調(diào)用過程剃幌,可以通過分析這段時(shí)間內(nèi)的函數(shù)調(diào)用流程,再進(jìn)一步分析待優(yōu)化的點(diǎn)晾浴。
第二個(gè)流派是 sample负乡。有選擇性或者采用抽樣的方式觀察某些函數(shù)調(diào)用過程,可以通過這些有限的信息推測出流程中的可疑點(diǎn)脊凰,然后再繼續(xù)細(xì)化分析抖棘。
TraceView屬于instrument類型,試圖收集某個(gè)階段所有函數(shù)的運(yùn)行信息,它希望在你并不知道哪個(gè)函數(shù)有問題的時(shí)候直接定位到關(guān)鍵函數(shù)钉答;但可惜的是础芍,收集所有信息 這個(gè)是不現(xiàn)實(shí)的,它的運(yùn)行時(shí)開銷嚴(yán)重干擾了運(yùn)行環(huán)境.
SYSTrace屬于sample類型数尿,它的思想很樸素仑性,在系統(tǒng)的一些關(guān)鍵鏈路(比如System Service,虛擬機(jī)右蹦,Binder驅(qū)動(dòng))插入一些信息(我這里稱之為Label)诊杆,通過Label的開始和結(jié)束來確定某個(gè)核心過程的執(zhí)行時(shí)間,然后把這些Label信息收集起來得到系統(tǒng)關(guān)鍵路徑的運(yùn)行時(shí)間信息何陆,進(jìn)而得到整個(gè)系統(tǒng)的運(yùn)行性能信息晨汹。Android Framework里面一些重要的模塊都插入了Label信息(Java層的通過android.os.Trace類完成,native層通過ATrace宏完成)贷盲,用戶App中可以添加自定義的Label淘这,這樣就組成了一個(gè)完成的性能分析系統(tǒng)。
在 Android Studio 3.2 的 Profiler 中直接集成了幾種性能分析工具巩剖,其中:Sample Java Methods 的功能類似于 Traceview 的 sample 類型铝穷。Trace Java Methods 的功能類似于 Traceview 的 instrument 類型。Trace System Calls 的功能類似于 systrace佳魔。SampleNative (API Level 26+) 的功能類似于 Simpleperf曙聂。坦白來說,Profiler 界面在某些方面不如這些工具自帶的界面鞠鲜,支持配置的參數(shù)也不如命令行宁脊,不過 Profiler 的確大大降低了開發(fā)者的使用門檻。
CPU profiler 存在于Android profile中贤姆,用于分析CUP動(dòng)態(tài)使用率榆苞,還可以分析函數(shù)調(diào)用關(guān)系,顯示線程任務(wù)的CPU使用率霞捡,它是TraceView和SYSTrace的替代工具
Tracer for OpenGL ES语稠,它可以記錄和分析app每一幀的繪制過程,以及列出所有用到OpenGL ES的繪制函數(shù)和耗時(shí)弄砍,所以通過Tracer for OpenGL ES我們可以很容易的看出app的每一幀是怎么畫出來的仙畦。已經(jīng)被Graphics API Debugger取代
LayoutInspector 查看運(yùn)行時(shí)的view結(jié)構(gòu)層級(jí),用來取代Hierarchy Viewer音婶,同樣取代了Pixel Perfect
Network Traffic tool If you need to view how and when your app transfers data over a network, use the Network Profiler
https://developer.android.google.cn/studio/profile/monitor.html
此外慨畸,優(yōu)化過程中使用低端手機(jī)更易發(fā)現(xiàn)瓶頸