[最新]android APP性能優化總結

前述

一個好的app除了有吸引人的功能, 美麗的交互之外,性能也至關重要,作為一個技術人員,在這里當然只能講技術了

一般app性能優化主要從一下幾個方面入手,

  • 啟動速度優化
  • app卡頓,流暢度優化
  • 內存優化
  • 代碼優化
  • apk瘦身優化
  • 電量優化
  • 穩定性優化

啟動速度優化

對于app啟動的優化,一般啟動的時候設置一個主題/圖片防止白屏或者延遲打開

 <style name="appTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowFullscreen">true</item>
    </style>

如果啟動頁面不是一張圖片,而且通過布局顯示可以利用Splash加載部分圖片先顯示出來

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--白色矩形 作為背景色-->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white" />
        </shape>
    </item>

    <!--單獨的slogan圖片 并且設置下間距-->
    <item android:bottom="0dp">
        <!--位置設置成靠下-->
        <bitmap
            android:gravity="bottom"
            android:src="@mipmap/bg_load_button" />
    </item>
</layer-list>

在5.0后,增加了一個windowDrawsSystemBarBackgrounds屬性,用來標志此窗口是否負責繪制系統欄背景,我們把它設成false,這樣當它繪制windowBackground的時候,就會在NavigationBar之上。
因為這個屬性是5.0以后才有的,所以需要新建values-v21文件夾,以便5.0以上的機器使用v21的Splash主題。

針對啟動速度慢,需要盡可能減少Applicatio和啟動頁面的onCreate中所要做的事情,比如一些不重要的SDK延遲或者異步加載;部分第三方的初始化(如極光的初始化就很耗時)可以使用到的類異步加載;如果對于設備5.0以下,還要考慮multidex的優化.提高啟動頁面響應速度,一般點擊app進入到首頁不能超過3秒,如果超過3秒就應該要做處理了.

對于如何檢測方法耗時,除了打印log,adb命令可以使用TraceView去看,后面我們會講到

卡頓優化

談到UI流暢度,一般就是不要在主進程去做耗時的操作,提升UI的繪制速度,下面幾點需要注意

  • 不要在主線程進行網絡訪問/大文件的IO操作

  • 繪制UI時,盡量減少繪制UI層次;減少不必要的view嵌套,減少重復繪制,可以用Hierarchy Viewer工具來檢測,后面會詳細講;

  • 當我們的布局是用的FrameLayout的時候,我們可以把它改成merge,可以避免自己的幀布局和系統的ContentFrameLayout幀布局重疊造成重復計算(measure和layout)
    參考鏈接

  • 提高顯示速度,使用ViewStub:當加載的時候才會占用。不加載的時候就是隱藏的,僅僅占用位置。

  • 在view層級相同的情況下,盡量使用 LinerLayout而不是RelativeLayout;因為RelativeLayout在測量的時候會測量二次,而LinerLayout測量一次,可以看下它們的源碼;

  • 刪除控件中無用的屬性;

  • 布局復用.比如listView 布局復用

  • 盡量避免過度繪制(overdraw)比如:背景經常容易造成過度繪制。由于我們布局設置了背景,同時用到的MaterialDesign的主題會默認給一個背景。這時應該把主題添加的背景去掉;還有移除 XML 中非必須的背景

  • 自定義View優化。使用 canvas.clipRect()來幫助系統識別那些可見的區域,只有在這個區域內才會被繪制。也是避免過度繪制.

  • 合理的刷新機制,盡量減少刷新次數,盡量避免后臺有高的 CPU 線程運行,縮小刷新區域。

  • 采用開銷較低的布局:例如,您可能會發現,TableLayout 作為具有許多位置依賴項的更復雜的布局,可以提供相同的功能。在 Android 的 N 版本中,ConstraintLayout 類提供了與 RelativeLayout 類似的功能,但開銷要低得多。

性能問題并不容易復現,也不好定位,下面介紹幾個非常有用的工具分析卡頓

  • 1.Profile GPU Rendering
    在手機開發者模式下,有一個卡頓檢測工具叫做:Profile GPU Rendering

    image.png

    下面用一張圖來解析各個顏色對應的意思(特別需要注意的我紅色框了出來)
    image.png

    總之,保持動畫流暢的關鍵就在于讓這些垂直的柱狀條盡可能地保持在綠線下面,任何時候超過綠線,你就有可能丟失一幀的內容.

  • 2.Debug GPU overDraw過度繪制檢測
    在手機開發者模式下,有一個過度繪制檢測工具叫做:Debug GPU overDraw,看圖:

    image.png

各個顏色代表的意義
Android 將按如下方式為界面元素著色,以確定過度繪制的次數:
真彩色:沒有過度繪制
藍色:過度繪制 1 次
綠色:過度繪制 2 次
粉色:過度繪制 3 次
紅色:過度繪制 4 次或更多次

總之,盡量避免過度繪制,常見的就是設置了多個背景顏色造成

內存優化

在開發的過程,如果方法不當的話,很容易造成內存泄漏,接下來,來說一下哪些情景容易出現內存泄漏。

內存泄漏出現的情景
  • 單例中引用的上下文Context,引用了Activity中的Context, 這樣會造成內存泄漏,要引用Application中的Context;()參考文章

  • 盡量不要在Activity中使用非靜態內部類,因為非靜態內部類會隱式持有外部類實例的引用,如果使用靜態內部類,將外部實例引用作為弱引用持有。

  • 資源性對象未關閉。比如Cursor、File文件等,往往都用了一些緩沖,在不使用時,應該及時關閉它們。參考文章

  • 注冊對象未注銷。比如事件注冊后未注銷,會導致觀察者列表中維持著對象的引用。類的靜態變量持有大數據對象。例如EventBus或者RxJava

  • 使用MMKV替換SharePreference(就是以鍵值對形式存在xml文件中)
    速度優勢:寫入速度是SharedPreferences的100倍左右。在主線程做IO存儲 用mmkv一點問題都沒有,不會出現卡頓情況,特別是在數據量比較大的時候,速度會一直保持在10ms以內
    寫入安全:通過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往里面寫數據,由操作系統負責將內存回寫到文件,不必擔心 crash 導致數據丟失。
    寫入優化:SharedPreferences在本身數據量比較多的情況下,更新一個key-value時,會發生全量寫入,意味著時間更長。mmkv避免了這種情況的出現。mmkv以增量方式進行寫入
    功能更全:支持多進程訪問,支持數據加密。多線程安全寫入
    參考文件

  • 非靜態內部類的靜態實例。參考文章

public class LayoutPerActivity extends Activity {
        private static TestModule mTestModule = null;
        @override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.getWindow().setBackgroundDrawable(null);
            setContentView(R.layout.activity_layout_per);
            if(null == mTestModule) {
                mTestModule = new TestModule(this);
            }
        }
        class TestModule{
            private Context mContext = null;
            public TestModule(Context ctx) {
                mContext = ctx;
            }
        }
    }
  • Handler臨時性內存泄漏。如果Handler是非靜態的,容易導致 Activity 或 Service 不會被回收,或者可以使用弱引用持有對Activity的引用。

  • 容器中的對象沒清理造成的內存泄漏。

  • WebView。WebView 存在著內存泄漏的問題,在應用中只要使用一次 WebView,內存就不會被釋放掉。參考資料

內存優化的方案
  • 對象引用。強引用、軟引用、弱引用、虛引用四種引用類型,根據業務需求合理使用不同,選擇不同的引用類型。
  • 減少不必要的內存開銷。注意自動裝箱,增加內存復用,比如有效利用系統自帶的資源、視圖復用、對象池、Bitmap對象的復用。
  • 使用最優的數據類型。比如針對數據類容器結構,可以使用ArrayMap數據結構,避免使用枚舉類型,使用緩存Lrucache等等。
  • 圖片內存優化。可以設置位圖規格,根據采樣因子做壓縮,用一些圖片緩存方式對圖片進行管理等等。

除此之外,內存泄漏可監控, 推薦square公司開源的Leakcanary可以在發生內存泄漏時告警,并且生成 leak tarce 分析泄漏位置,同時可以提供 Dump 文件進行分析。

內存分析工具

以下介紹幾種內存分析工具

  • Memory Monitor
    Memory Monitor 是一款使用非常簡單的圖形化工具,可以很好地監控系統或應用的內存使用情況.
    主要有以下功能:

(1).顯示可用和已用內存,并且以時間為維度實時反應內存分配和回收情況。
(2).快速判斷應用程序的運行緩慢是否由于過度的內存回收導致。
(3).快速判斷應用是否由于內存不足導致程序崩潰。

  • Allocation Tracker

Memory Monitor 和 Heap Viewer 都可以很直觀且實時地監控內存使用情況,還能發現內存問題,但發現內存問題后不能再進一步找到原因,或者發現一塊異常內存,但不能區別是否正常,同時在發現問題后,也不能定位到具體的類和方法。這時就需要使用另一個內存分析工具 Allocation Tracker,進行更詳細的分析, Allocation Tracker 可以分配跟蹤記錄應用程序的內存分配,并列出了它們的調用堆棧,可以查看所有對象內存分配的周期。

  • Memory Analyzer Tool(MAT)

MAT 是一個快速,功能豐富的 Java Heap 分析工具,通過分析 Java 進程的內存快照 HPROF 分析,從眾多的對象中分析,快速計算出在內存中對象占用的大小,查看哪些對象不能被垃圾收集器回收,并可以通過視圖直觀地查看可能造成這種結果的對象。

  • AndroidPerformanceMonitor
    非侵入式的性能監控組件,通知形式彈出卡頓信息
    implementation 'com.github.markzhai:blockcanary-android:1.5.0'
    當我們把程序運行之后,會發現手機桌面上出現了一個Blocks的圖標,這個玩意和之前我們使用LeakCanary的時候有點像哈,然后點進去果然發現了剛剛的Block信息

代碼優化

關于代碼優化,有這么一個很好用的工具Android lint
在頂部菜單欄找到Analyze選項,在彈框中選中Inspect Code,或者對項目根雙擊彈出菜單彈框(windows下右鍵項目根目錄),找到Analyze選項再選中Inspect Code選項


image.png

Correctness:不夠完美的編碼,比如硬編碼、使用過時 API 等
Performance:對性能有影響的編碼,比如:靜態引用,循環引用等
Internationalization:國際化,直接使用漢字,沒有使用資源引用等
Security:不安全的編碼,比如在 WebView 中允許使用 JavaScriptInterface
Remove All Unused Resources的選項,先全部清理,考慮反射機制,不能刪除資源

Handler Reference leaks,當使用內部類(包括匿名類)來創建Handler的時候,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View?)。而Handler通常會伴隨著一個耗時的后臺線程(例如從網絡拉取圖片)一起出現,這個后臺線程在任務執行完畢(例如圖片下載完畢)之后,通過消息機制通知Handler,然后Handler把圖片更新到界面。然而,如果用戶在網絡請求過程中關閉了Activity,正常情況下,Activity不再被使用,它就有可能在GC檢查時被回收掉,但由于這時線程尚未執行完,而該線程持有Handler的引用(不然它怎么發消息給Handler?),這個Handler又持有Activity的引用,就導致該Activity無法被回收(即內存泄露),直到網絡請求結束(例如圖片下載完畢)。另外,如果你執行了Handler的postDelayed()方法,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中,那么在你設定的delay到達之前,會有一條MessageQueue -> Message -> Handler -> Activity的鏈,導致你的Activity被持有引用而無法被回收。這個問題也是較常見的可能導致內存泄漏的問題,解決方法一般是通過弱引用持有對Activity的引用

Android代碼優化——Layout Inspector
當您的布局在運行時構建而不是完全在XML布局中定義時,這尤其有用
Layout Inspector主要用分析布局的層級結構,減少不必要的層級,避免overdraw, 達到渲染優化的效果。Layout Inspector雖然界面不如HierarchyView直觀,但是提供的信息也足夠詳細,分析布局層級絕對夠用了。

Android代碼優化---traceview使用
Debug.startMethodTracing(“hello”); Debug.stopMethodTracing();
TraceView 是 Android SDK 中內置的一個工具,它可以加載 trace 文件,用圖形的形式展示代碼的執行時間、次數及調用棧,便于我們分析。

trace 文件是 log 信息文件的一種,可以通過代碼,Android Studio,或者 DDMS 生成。

image.png

使用luban壓縮 是通過原生的bitmap.compress() 是1000倍,參考微信,手機拍照幾M上傳上去就幾十KB

耗電優化

在移動設備中,電池的重要性不言而喻,沒有電什么都干不成。對于操作系統和設備開發商來說,耗電優化一致沒有停止,去追求更長的待機時間,而對于一款應用來說,并不是可以忽略電量使用問題,特別是那些被歸為“電池殺手”的應用,最終的結果是被卸載。因此,應用開發者在實現需求的同時,需要盡量減少電量的消耗。 耗電的原因其實很多,這里我就講一下幾種優化方案,優化方案的反面就是他的原因了,幾種優化方案如下:

  • 合理的使用wack_lock鎖,wake_lock鎖主要是相對系統的休眠(這里就是為了省電,才做休)而言的,意思就是我的程序給CPU加了這個鎖那系統就不會休眠了,這樣做的目的是為了全力配合我們程序的運行。有的情況如果不這么做就會出現一些問題,比如微信等及時通訊的心跳包會在熄屏不久后停止網絡訪問等問題。所以微信里面是有大量使用到了wake_lock鎖。這里有一篇關于wake_lock的使用,請查閱

  • 使用jobScheduler2,集中處理一些網絡請求,有些不用很及時的處理可以放在充電的時候處理,比如,圖片的處理,APP下載更新等等,這里有一篇關于jobScheduler的使用,請查閱

  • 計算優化,避開浮點運算等。

  • 數據在網絡上傳輸時,盡量壓縮數據后再傳輸,建議用FlatBuffer序列化技術,這個比json效率高很多倍,不了解FlatBuffer,建議找資料學習一下,后面有時間的話,也會專門寫關于FlatBuffer的文章.

andriod耗電分析所用到的工具

在 Android5.0 以前,在應用中測試電量消耗比較麻煩,也不準確,5.0 之后專門引入了一個獲取設備上電量消耗信息的 API:Battery Historian。Battery Historian 是是一款圖形化數據分析工具,直觀地展示出手機的電量消耗過程,通過輸入電量分析文件,顯示消耗情況;

安裝包大小優化

隨著功能不斷增加,APP的包肯定不會斷的變大,但應用的安裝包越大,用戶下載的門檻越高,特別是在移動網絡情況下,用戶在下載應用時,對安裝包大小的要求更高,因此,減小安裝包大小可以讓更多用戶愿意下載和體驗產品。所以,我們還是要想辦法去如何去優化,盡量減小app的安排包.

APP包優化方案
  • res資源優化
    (1)只盡量使用一套圖片,使用高分辨率的圖片。
    (2)UI設計在ps安裝TinyPNG插件,對圖片進行無損壓縮。
    (3)svg圖片:一些圖片的描述,犧牲CPU的計算能力的,節省空間。使用的原則:簡單的圖標。
    (4)圖片使用WebP(developers.google.com/speed/webp/)的格式(Facebook、騰訊、淘寶在用。)缺點:加載相比于PNG要慢很多。 但是配置比較高。工具: isparta.github.io/
    (5)使用tintcolor(android - Change drawable color programmatically)實現按鈕反選效果。
  • 代碼優化
    (1)實現功能模塊的邏輯簡化
    (2)Lint工具檢查無用文件將無用的資源列在“UnusedResources: Unused resources”,刪除。
    (3)移除無用的依賴庫。
  • lib資源優化
    (1)動態下載的資源。
    (2)一些模塊的插件化動態添加。
    (3)so文件的剪裁和壓縮。
  • assets資源優化
    (1)音頻文件最好使用有損壓縮的格式,比如采用opus、mp3等格式,但是最好不要使用無損壓縮的音樂格式
    (2)對ttf字體文件壓縮,可以采用FontCreator工具只提取出你需要的文字。比如在做日期顯示時,其實只需要數字字體,但是使用原有的字體庫可能需要10MB大小,如果只是把你需要的字體提取出來生成的字體文件只有10KB
  • 代碼混淆。
    使用proGuard 代碼混淆器工具,它包括壓縮、優化、混淆等功能。
  • 7z極限壓縮
    具體請參考微信的安接包壓縮,實現實現原理,有時間再分析;

穩定性優化

Android 應用的穩定性定義很寬泛,影響穩定性的原因很多,比如內存使用不合理、代碼異常場景考慮不周全、代碼邏輯不合理等,都會對應用的穩定性造成影響。其中最常見的兩個場景是:Crash 和 ANR,這兩個錯誤將會使得程序無法使用,比較常用的解決方式如下:

  • 提高代碼質量。比如開發期間的代碼審核,看些代碼設計邏輯,業務合理性等。

  • 代碼靜態掃描工具。常見工具有Android Lint、Findbugs、Checkstyle、PMD等等。

  • Crash監控。把一些崩潰的信息,異常信息及時地記錄下來,以便后續分析解決。

  • Crash上傳機制。在Crash后,盡量先保存日志到本地,然后等下一次網絡正常時再上傳日志信息。

  • 適當緩存,可讓App看起來更快。
    使用DiskLruCache

總結

其實app性能優化,不是一二天可以完成的,不斷的提高開發的質量,發現了問題,就要及時的解決,不能推三拉四,這次就總結到這里,本人也是小白,希望能能夠和大家一起學習.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容