騰訊,阿里,百度Android高階崗;全方位效能調優技術體系詳解

Android架構技術分享發表於2019-04-28

前言

很多人對大廠的印象是;面試造飛機,工作擰螺絲。

用造飛機的能力去擰螺絲,形象的說明了大廠裡的技術標準是遠高於在小公司搬程式碼的。在具備java語言,設計模式,資料結構演算法技能能基礎之上,效能調優是關鍵點

這篇文章希望給大家介紹一下目前那些一線公司Android開發中效能調優最常用的方法,後面會再把那些效能調優的技術解析文章分享給大家,歡迎持續關注~

騰訊,阿里,百度Android高階崗;全方位效能調優技術體系詳解

全方位效能優化方法

1,佈局優化

佈局優化的思想很簡單,就是儘量減少佈局檔案的層級,佈局中的層級少了,這就意味著Android繪製時的工作量少了,那麼程式的效能自然就高了。
那麼如何進行佈局優化呢?有以下兩點:
•首先刪除佈局中無用的看控制元件和層級,其次有選擇地使用效能較低的ViewGroup,比如RelativeLayout。
•可以採用標籤、標籤、ViewStub。標籤主要用於佈局重用,標籤一般配合標籤使用,它可以降低減少佈局的層級,而ViewStub則提供了按需載入的功能。

2,繪製優化

繪製優化是指View的onDraw方法要避免執行大量的操作,主要體現在兩個方面
•onDraw中不要建立新的區域性物件,這是因為onDraw方法可能會被頻繁呼叫,這樣就會在一瞬間產生大量的臨時物件,這不僅佔用了過多的記憶體而且還會導致系統會更頻繁gc,降低程式的執行效率。
•onDraw方法中不要做耗時的任務,也不能執行成千上萬次的迴圈操作,儘管每次迴圈都很輕量級,但是大量的迴圈仍然十分搶佔CPU的時間片,這會造成View的繪製過程很不流暢。

3,記憶體優化

記憶體洩露在開發過程中是一個需要重視的問題,記憶體優化分為兩個方面,一方面是在開發過程中避免寫出有記憶體洩露的程式碼,另一方面是通過一些分析工具比如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:單例模式導致記憶體洩露
靜態變數導致的記憶體洩露都太過明顯了,但單例模式所帶來的記憶體洩露是我們容易忽視的。比如下面這段程式碼:

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();
    }
複製程式碼
4,響應速度優化和ANR日誌分析

響應速度優化的核心思想是避免在主執行緒中做耗時操作,但是有時候的確有很多耗時操作,怎麼辦呢?可以將這些耗時操作放線上程中去執行,即採用非同步的方式執行耗時操作。響應速度過慢更多地體現在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);
    }
複製程式碼
5,ListView和Bitmap優化

ListView優化三個方面:
•採用ViewHolder並避免在getView中執行耗時操作
•根據列表的滑動狀態來控制任務的執行頻率,比如當列表快速滑動時顯然是不太適合開啟大量非同步任務的。
•嘗試開啟硬體加速來使ListView的滑動更加流暢。
Bitmap優化,主要是通過BitmapFactory.Options來根據需要對圖片進行取樣,取樣過程中主要用到了BitmapFactory.Option的inSampleSize引數。

6,執行緒優化

執行緒優化的思想是採用執行緒池,避免在程式中存在大量的Thread。執行緒池可以重用內部的執行緒,從而避免了現場的建立和銷燬所帶來的效能開銷,同時執行緒池還能有效地控制執行緒池的最大併發數,避免大量的執行緒因互相搶佔系統資源從而導致阻塞現象發生。

7,其他效能優化建議

還有一些其他效能優化的小建議,通過它們可以在一定程度上提高效能:
•避免建立過多的物件
•不要過多使用列舉,列舉佔用的記憶體空間要比整型大
•常量請用static final來修飾
•使用一些Android特有的資料結構,比如SpareArray和Pair等,它們都具有更好的效能
•適當使用軟引用和弱引用
•採用記憶體快取和磁碟快取
•儘量採用靜態內部類,這樣可以避免在的由於內部類而導致的記憶體洩露
提高程式的可維護性
主要是提高程式碼的可維護性和可擴充套件性,而程式的可維護性本質上也包含可擴充套件性。
•命名要規範,要能正確地傳達出變數或者方法的含義,少用縮寫,關於變數的字首可以參考Android原始碼的命名方式,比如私有方式以m開頭,靜態成員以s開頭,常量則全部用大寫字母表示,等等。
•程式碼的排版上需要留出合理的空白區分不同的程式碼塊,其中同類變數的宣告要放在一組,兩類變數之間要留出一行空白作為區分。
•僅為非常關鍵的程式碼新增註釋,其他地方不寫註釋,這就對變數和方法的命名風格提出了很高的要求。
•程式碼的層次性指程式碼要有分層的概念,對於一段業務邏輯,不要試圖在一個方法或者一個類中去全部實現,它可以分成幾個子邏輯,然後每個子邏輯做自己的事情。單一職責是和層次性相關聯,程式碼分成以後,每一層僅僅關注少量的邏輯,這樣就做到了單一職責。

效能調優技術大綱;

效能優化系列文章;

效能調優;如何讓你的APK瘦身88%!

Android高階效能調優;不可思議的OOM!

騰訊,阿里,百度Android高階崗;全方位效能調優技術體系詳解

BAT主流Android高階架構技術大綱+學習路線+資料分享

架構技術詳解,學習路線與資料分享都在部落格這篇文章裡《BATJ一線大廠最主流的Android高階架構技術;體系詳解+學習路線》
(包括自定義控制元件、NDK、架構設計、混合式開發工程師(React native,Weex)、效能優化、完整商業專案開發等)

  • 阿里P8級Android架構師技術腦圖

騰訊,阿里,百度Android高階崗;全方位效能調優技術體系詳解

  • 全套體系化高階架構視訊;七大主流技術模組,視訊+原始碼+筆記

騰訊,阿里,百度Android高階崗;全方位效能調優技術體系詳解


相關文章