您好,登錄后才能下訂單哦!
很多人對大廠的印象是;面試造飛機(jī),工作擰螺絲。
用造飛機(jī)的能力去擰螺絲,形象的說明了大廠里的技術(shù)標(biāo)準(zhǔn)是遠(yuǎn)高于在小公司搬代碼的。在具備java語言,設(shè)計模式,數(shù)據(jù)結(jié)構(gòu)算法技能能基礎(chǔ)之上,性能調(diào)優(yōu)是關(guān)鍵點(diǎn)
這篇文章希望給大家介紹一下目前那些一線公司Android開發(fā)中性能調(diào)優(yōu)最常用的方法,后面會再把那些性能調(diào)優(yōu)的技術(shù)解析文章分享給大家,歡迎持續(xù)關(guān)注~
布局優(yōu)化的思想很簡單,就是盡量減少布局文件的層級,布局中的層級少了,這就意味著Android繪制時的工作量少了,那么程序的性能自然就高了。
那么如何進(jìn)行布局優(yōu)化呢?有以下兩點(diǎn):
?首先刪除布局中無用的看控件和層級,其次有選擇地使用性能較低的ViewGroup,比如RelativeLayout。
?可以采用標(biāo)簽、標(biāo)簽、ViewStub。標(biāo)簽主要用于布局重用,標(biāo)簽一般配合標(biāo)簽使用,它可以降低減少布局的層級,而ViewStub則提供了按需加載的功能。
繪制優(yōu)化是指View的onDraw方法要避免執(zhí)行大量的操作,主要體現(xiàn)在兩個方面
?onDraw中不要創(chuàng)建新的局部對象,這是因為onDraw方法可能會被頻繁調(diào)用,這樣就會在一瞬間產(chǎn)生大量的臨時對象,這不僅占用了過多的內(nèi)存而且還會導(dǎo)致系統(tǒng)會更頻繁gc,降低程序的執(zhí)行效率。
?onDraw方法中不要做耗時的任務(wù),也不能執(zhí)行成千上萬次的循環(huán)操作,盡管每次循環(huán)都很輕量級,但是大量的循環(huán)仍然十分搶占CPU的時間片,這會造成View的繪制過程很不流暢。
內(nèi)存泄露在開發(fā)過程中是一個需要重視的問題,內(nèi)存優(yōu)化分為兩個方面,一方面是在開發(fā)過程中避免寫出有內(nèi)存泄露的代碼,另一方面是通過一些分析工具比如MAT來找出潛在的內(nèi)存泄露繼而解決。
場景1:靜態(tài)變量導(dǎo)致內(nèi)存泄露
比如下面這段代碼:
public?class?MainActivity?extends?Activity?{????private?static?final?String?TAG?=?"MainActivity";????private?static?Context?sContext;????private?static?View?sView;????@Override ????protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState); ????????setContentView(R.layout.activity_main); ????????sContext?=?this; ????????sView?=?new?View(this); ????} }
MainActivity無法正常銷毀,因為靜態(tài)變量sContext引用了它。同樣,sView是一個靜態(tài)變量,他內(nèi)部持有了當(dāng)前Activity,所以Activity仍然無法釋放。
場景2:單例模式導(dǎo)致內(nèi)存泄露
靜態(tài)變量導(dǎo)致的內(nèi)存泄露都太過明顯了,但單例模式所帶來的內(nèi)存泄露是我們?nèi)菀缀鲆暤?。比如下面這段代碼:
public?class?TestManager?{????private?List<OnDataArrivedListener>?mOnDataArrivedListeners?=?new?ArrayList<OnDataArrivedListener>();????private?static?class?SingletonHolder?{????????public?static?final?TestManager?INSTANCE?=?new?TestManager(); ????}????private?TestManager()?{ ????}????public?static?TestManager?getInstance()?{????????return?SingletonHolder.INSTANCE; ????}????public?synchronized?void?registerListener(OnDataArrivedListener?listener)?{????????if?(!mOnDataArrivedListeners.contains(listener))?{ ????????????mOnDataArrivedListeners.add(listener); ????????} ????}????public?synchronized?void?unregisterListener(OnDataArrivedListener?listener)?{ ????????mOnDataArrivedListeners.remove(listener); ????}????public?interface?OnDataArrivedListener?{????????public?void?onDataArrived(Object?data); ????} }
首先提供一個單例模式的TestManager,TestManager可以接收外部的注冊并將外部的監(jiān)聽器存儲起來。然后用Activity實現(xiàn)OnDataArrivedListener接口并向TestManager注冊監(jiān)聽,但是如果缺少解注冊的操作,會引起內(nèi)存泄露。比如下面這段代碼:
?protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState); ????????setContentView(R.layout.activity_main); ????????TestManager.getInstance().registerListener(this); ????}
Activity的對象被單例模式的TestManager所持有,而單例模式的特點(diǎn)是其生命周期和Application保持一致,因此Activity對象無法被及時釋放。
場景3:屬性動畫導(dǎo)致的內(nèi)存泄露
從Android3.0開始,Google提供了屬性動畫,屬性動畫中有這么一類無限循環(huán)的動畫,如果在Activity中播放此類動畫且沒有在onDestroy中停止動畫,那么動畫就會一直播放下去,盡管已經(jīng)無法在界面上看到動畫效果,但這個時候Activity的View會被動畫持有,而View又持有了Activity,最終Activity無法釋放。
??protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState); ????????setContentView(R.layout.activity_main); ????????ObjectAnimator?animator?=?ObjectAnimator.ofFloat(mButton,?"rotation",0,?360).setDuration(2000); ????????animator.setRepeatCount(ValueAnimator.INFINITE); ????????animator.start();????????//animator.cancel(); ????}
響應(yīng)速度優(yōu)化的核心思想是避免在主線程中做耗時操作,但是有時候的確有很多耗時操作,怎么辦呢?可以將這些耗時操作放在線程中去執(zhí)行,即采用異步的方式執(zhí)行耗時操作。響應(yīng)速度過慢更多地體現(xiàn)在Activity的啟動速度上面,如果在主線程中做太多的事情,會導(dǎo)致Activity啟動出現(xiàn)黑屏現(xiàn)象,甚至出現(xiàn)ANR。Android規(guī)定,Activity如果5秒鐘之內(nèi)無法響應(yīng)屏幕觸摸事件或者鍵盤輸入事件就會出現(xiàn)ANR,而BroadcastReceiver如果10秒之內(nèi)還未執(zhí)行完操作也會出現(xiàn)ANR,那么在實際開發(fā)過程中遇到ANR,怎么定位問題呢?其實當(dāng)一個進(jìn)程發(fā)生ANR了以后,系統(tǒng)會在/data/anr/目錄下創(chuàng)建一個文件traces.txt,通過分析這個文件就能定位出ANR的原因。比如下面代碼在Activity的onCreate中休眠30s,程序運(yùn)行持續(xù)點(diǎn)擊屏幕,應(yīng)用一定會出現(xiàn)ANR:
?protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState); ????????setContentView(R.layout.activity_main); ????????SystemClock.sleep(30?*?1000); ????}
ListView優(yōu)化三個方面:
?采用ViewHolder并避免在getView中執(zhí)行耗時操作
?根據(jù)列表的滑動狀態(tài)來控制任務(wù)的執(zhí)行頻率,比如當(dāng)列表快速滑動時顯然是不太適合開啟大量異步任務(wù)的。
?嘗試開啟硬件加速來使ListView的滑動更加流暢。
Bitmap優(yōu)化,主要是通過BitmapFactory.Options來根據(jù)需要對圖片進(jìn)行采樣,采樣過程中主要用到了BitmapFactory.Option的inSampleSize參數(shù)。
線程優(yōu)化的思想是采用線程池,避免在程序中存在大量的Thread。線程池可以重用內(nèi)部的線程,從而避免了現(xiàn)場的創(chuàng)建和銷毀所帶來的性能開銷,同時線程池還能有效地控制線程池的最大并發(fā)數(shù),避免大量的線程因互相搶占系統(tǒng)資源從而導(dǎo)致阻塞現(xiàn)象發(fā)生。
還有一些其他性能優(yōu)化的小建議,通過它們可以在一定程度上提高性能:
?避免創(chuàng)建過多的對象
?不要過多使用枚舉,枚舉占用的內(nèi)存空間要比整型大
?常量請用static final來修飾
?使用一些Android特有的數(shù)據(jù)結(jié)構(gòu),比如SpareArray和Pair等,它們都具有更好的性能
?適當(dāng)使用軟引用和弱引用
?采用內(nèi)存緩存和磁盤緩存
?盡量采用靜態(tài)內(nèi)部類,這樣可以避免在的由于內(nèi)部類而導(dǎo)致的內(nèi)存泄露
提高程序的可維護(hù)性
主要是提高代碼的可維護(hù)性和可擴(kuò)展性,而程序的可維護(hù)性本質(zhì)上也包含可擴(kuò)展性。
?命名要規(guī)范,要能正確地傳達(dá)出變量或者方法的含義,少用縮寫,關(guān)于變量的前綴可以參考Android源碼的命名方式,比如私有方式以m開頭,靜態(tài)成員以s開頭,常量則全部用大寫字母表示,等等。
?代碼的排版上需要留出合理的空白區(qū)分不同的代碼塊,其中同類變量的聲明要放在一組,兩類變量之間要留出一行空白作為區(qū)分。
?僅為非常關(guān)鍵的代碼添加注釋,其他地方不寫注釋,這就對變量和方法的命名風(fēng)格提出了很高的要求。
?代碼的層次性指代碼要有分層的概念,對于一段業(yè)務(wù)邏輯,不要試圖在一個方法或者一個類中去全部實現(xiàn),它可以分成幾個子邏輯,然后每個子邏輯做自己的事情。單一職責(zé)是和層次性相關(guān)聯(lián),代碼分成以后,每一層僅僅關(guān)注少量的邏輯,這樣就做到了單一職責(zé)。
架構(gòu)技術(shù)詳解和學(xué)習(xí)路線與資料分享請看這篇《BATJ一線大廠最主流的Android高級架構(gòu)技術(shù);體系詳解+學(xué)習(xí)路線》
(包括自定義控件、NDK、架構(gòu)設(shè)計、混合式開發(fā)工程師(React native,Weex)、性能優(yōu)化、完整商業(yè)項目開發(fā)等)
阿里P8級Android架構(gòu)師技術(shù)腦圖;
全套體系化高級架構(gòu)視頻;七大主流技術(shù)模塊,視頻+源碼+筆記
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。