不少人對大廠的印象是;面試造飛機,工做擰螺絲。java
用造飛機的能力去擰螺絲,形象的說明了大廠裏的技術標準是遠高於在小公司搬代碼的。在具有java語言,設計模式,數據結構算法技能能基礎之上,性能調優是關鍵點面試
這篇文章但願給你們介紹一下目前那些一線公司Android開發中性能調優最經常使用的方法,後面會再把那些性能調優的技術解析文章分享給你們,歡迎持續關注~算法
佈局優化的思想很簡單,就是儘可能減小布局文件的層級,佈局中的層級少了,這就意味着Android繪製時的工做量少了,那麼程序的性能天然就高了。
那麼如何進行佈局優化呢?有如下兩點:
•首先刪除佈局中無用的看控件和層級,其次有選擇地使用性能較低的ViewGroup,好比RelativeLayout。
•能夠採用標籤、標籤、ViewStub。標籤主要用於佈局重用,標籤通常配合標籤使用,它能夠下降減小布局的層級,而ViewStub則提供了按需加載的功能。設計模式
繪製優化是指View的onDraw方法要避免執行大量的操做,主要體如今兩個方面
•onDraw中不要建立新的局部對象,這是由於onDraw方法可能會被頻繁調用,這樣就會在一瞬間產生大量的臨時對象,這不只佔用了過多的內存並且還會致使系統會更頻繁gc,下降程序的執行效率。
•onDraw方法中不要作耗時的任務,也不能執行成千上萬次的循環操做,儘管每次循環都很輕量級,可是大量的循環仍然十分搶佔CPU的時間片,這會形成View的繪製過程很不流暢。緩存
內存泄露在開發過程當中是一個須要重視的問題,內存優化分爲兩個方面,一方面是在開發過程當中避免寫出有內存泄露的代碼,另外一方面是經過一些分析工具好比MAT來找出潛在的內存泄露繼而解決。
場景1:靜態變量致使內存泄露
好比下面這段代碼:性能優化
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沒法正常銷燬,由於靜態變量sContext引用了它。一樣,sView是一個靜態變量,他內部持有了當前Activity,因此Activity仍然沒法釋放。
場景2:單例模式致使內存泄露
靜態變量致使的內存泄露都太過明顯了,但單例模式所帶來的內存泄露是咱們容易忽視的。好比下面這段代碼:markdown
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能夠接收外部的註冊並將外部的監聽器存儲起來。而後用Activity實現OnDataArrivedListener接口並向TestManager註冊監聽,可是若是缺乏解註冊的操做,會引發內存泄露。好比下面這段代碼:數據結構
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TestManager.getInstance().registerListener(this); } 複製代碼
Activity的對象被單例模式的TestManager所持有,而單例模式的特色是其生命週期和Application保持一致,所以Activity對象沒法被及時釋放。
場景3:屬性動畫致使的內存泄露
從Android3.0開始,Google提供了屬性動畫,屬性動畫中有這麼一類無限循環的動畫,若是在Activity中播放此類動畫且沒有在onDestroy中中止動畫,那麼動畫就會一直播放下去,儘管已經沒法在界面上看到動畫效果,但這個時候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(); } 複製代碼
響應速度優化的核心思想是避免在主線程中作耗時操做,可是有時候的確有不少耗時操做,怎麼辦呢?能夠將這些耗時操做放在線程中去執行,即採用異步的方式執行耗時操做。響應速度過慢更多地體如今Activity的啓動速度上面,若是在主線程中作太多的事情,會致使Activity啓動出現黑屏現象,甚至出現ANR。Android規定,Activity若是5秒鐘以內沒法響應屏幕觸摸事件或者鍵盤輸入事件就會出現ANR,而BroadcastReceiver若是10秒以內還未執行完操做也會出現ANR,那麼在實際開發過程當中遇到ANR,怎麼定位問題呢?其實當一個進程發生ANR了之後,系統會在/data/anr/目錄下建立一個文件traces.txt,經過分析這個文件就能定位出ANR的緣由。好比下面代碼在Activity的onCreate中休眠30s,程序運行持續點擊屏幕,應用必定會出現ANR:併發
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SystemClock.sleep(30 * 1000); } 複製代碼
ListView優化三個方面:
•採用ViewHolder並避免在getView中執行耗時操做
•根據列表的滑動狀態來控制任務的執行頻率,好比當列表快速滑動時顯然是不太適合開啓大量異步任務的。
•嘗試開啓硬件加速來使ListView的滑動更加流暢。
Bitmap優化,主要是經過BitmapFactory.Options來根據須要對圖片進行採樣,採樣過程當中主要用到了BitmapFactory.Option的inSampleSize參數。
線程優化的思想是採用線程池,避免在程序中存在大量的Thread。線程池能夠重用內部的線程,從而避免了現場的建立和銷燬所帶來的性能開銷,同時線程池還能有效地控制線程池的最大併發數,避免大量的線程因互相搶佔系統資源從而致使阻塞現象發生。
還有一些其餘性能優化的小建議,經過它們能夠在必定程度上提升性能:
•避免建立過多的對象
•不要過多使用枚舉,枚舉佔用的內存空間要比整型大
•常量請用static final來修飾
•使用一些Android特有的數據結構,好比SpareArray和Pair等,它們都具備更好的性能
•適當使用軟引用和弱引用
•採用內存緩存和磁盤緩存
•儘可能採用靜態內部類,這樣能夠避免在的因爲內部類而致使的內存泄露
提升程序的可維護性
主要是提升代碼的可維護性和可擴展性,而程序的可維護性本質上也包含可擴展性。
•命名要規範,要能正確地傳達出變量或者方法的含義,少用縮寫,關於變量的前綴能夠參考Android源碼的命名方式,好比私有方式以m開頭,靜態成員以s開頭,常量則所有用大寫字母表示,等等。
•代碼的排版上須要留出合理的空白區分不一樣的代碼塊,其中同類變量的聲明要放在一組,兩類變量之間要留出一行空白做爲區分。
•僅爲很是關鍵的代碼添加註釋,其餘地方不寫註釋,這就對變量和方法的命名風格提出了很高的要求。
•代碼的層次性指代碼要有分層的概念,對於一段業務邏輯,不要試圖在一個方法或者一個類中去所有實現,它能夠分紅幾個子邏輯,而後每一個子邏輯作本身的事情。單一職責是和層次性相關聯,代碼分紅之後,每一層僅僅關注少許的邏輯,這樣就作到了單一職責。
性能優化系列文章;
架構技術詳解,學習路線與資料分享都在博客這篇文章裏《BATJ一線大廠最主流的Android高級架構技術;體系詳解+學習路線》
(包括自定義控件、NDK、架構設計、混合式開發工程師(React native,Weex)、性能優化、完整商業項目開發等)