前述
最近在做app性能優化,這裡做一個總結,供大家了解學習,也友善自己以後查閱.
用android的同學都知道,新買的手機用過一段時間後,手機變得越來越卡了;裝了一些APP後,電量用得飛快,一天基本要一充;有些APP打開半天加載不出來;有些APP進入某些頁面突然閃退;還有用了一些APP,流量用得飛快,幾百M的流量用了幾天就沒有了等等;
這是什麼原因呢?
- android系統源碼是開放的,可以對源碼的更改,像國内的幾大手機廠商,都是對系統進入定制開發,這樣就會引發一系列問題,比如說著名的系統碎片化問題;
- 各大廠商定制的系統,相容性肯定不好,開發人員要對各個系統做各種适配,還有開發人員的水準參次不齊,開發出來的APP就會出現這樣那樣的問題等等;
那我們又得如何處理這樣的問題呢?
那就是今天我們要說的APP性能優化,開發人員開發出來的app要性能好,使用者體驗好,性能好的APP總結一下,有如下幾點:
- APP使用起來不卡頓,要流暢;
- 要省電,省流量;
- 要穩定,不閃退(減少閃退,ANR率);
- APP包盡量要小;
要開發性能好的app,主要要達到以上四點;但是如何達到上面幾點呢,那我們得找到達不到的原因,下面我們一一來分析,并給出解決方案:
卡頓優化
Android 應用啟動慢,使用時經常卡頓,是非常影響使用者體驗的,應該盡量避免出現。總的來說造成卡頓的原因有如下幾種:
- UI的繪制。主要原因是繪制的層級深、頁面複雜、重新整理不合理,由于這些原因導緻卡頓的場景更多出現在 UI 和啟動後的初始界面以及跳轉到頁面的繪制上。
- 資料處理上。導緻這種卡頓場景的原因是資料處理量太大,一般分為三種情況,一是資料在主線程處理,這個是初級工程師會犯的錯誤,二是資料處理占用 CPU 高,導緻主線程拿不到時間片,三是記憶體增加導緻 GC 頻繁,進而引起卡頓。引起卡頓的原因很多,但不管怎麼樣的原因和場景,最終都是通過裝置螢幕上顯示來達到使用者,歸根到底就是顯示有問題,是以,要解決卡頓,就要先了解 Android 系統的渲染機制。
- UI的過度繪制,繪制的頁面有幾層View,底層View都是隐藏的,這種的還繪制的話就會造成過度繪制
andriod的渲染機制
要在螢幕上顯示,其實要經過一系列的過程,Android 應用程式把經過測量、布局、繪制後的 surface 緩存資料,通過 SurfaceFlinger 把資料渲染到顯示螢幕上, 通過 Android 的重新整理機制來重新整理資料。也就是說應用層負責繪制,系統層負責渲染,通過程序間通信把應用層需要繪制的資料傳遞到系統層服務,系統層服務通過重新整理機制把資料更新到螢幕上。
這裡我們先介紹一個名詞:FPS。FPS 表示每秒傳遞的幀數。在理想情況下,60 FPS 就感覺不到卡,這意味着每個繪制時長應該在16 ms 以内。但是 Android 系統很有可能無法及時完成那些複雜的頁面渲染操作。Android 系統每隔 16ms 發出 VSYNC 信号,觸發對 UI 進行渲染,如果每次渲染都成功,這樣就能夠達到流暢的畫面所需的 60FPS。如果某個操作花費的時間是 24ms ,系統在得到 VSYNC 信号時就無法正常進行正常渲染,這樣就發生了丢幀現象。那麼使用者在 32ms 内看到的會是同一幀畫面,這種現象在執行動畫或滑動清單比較常見,還有可能是你的 Layout 太過複雜,層疊太多的繪制單元,無法在 16ms 完成渲染,最終引起重新整理不及時。
android的View的繪制流程大家應該都知道,都是要經過三大核心步驟:Measure、Layout、Draw。具體是如何實作的建議看一下View的源碼,這裡我就不多說了;如果繪制的層級深,頁面複雜,在Measure、Layout這二個步驟要花費大量的時間;這樣也會造卡頓現象;
andriod卡頓優化方案
- 不要在主線程進行網絡通路/大檔案的IO操作
- 繪制UI時,盡量減少繪制UI層次;減少不必要的view嵌套,可以用Hierarchy Viewer工具來檢測,後面會詳細講;
- 當我們的布局是用的FrameLayout的時候,我們可以把它改成merge,可以避免自己的幀布局和系統的ContentFrameLayout幀布局重疊造成重複計算(measure和layout)
- 提高顯示速度,使用ViewStub:當加載的時候才會占用。不加載的時候就是隐藏的,僅僅占用位置。
- 在view層級相同的情況下,盡量使用 LinerLayout而不是RelativeLayout;因為RelativeLayout在測量的時候會測量二次,而LinerLayout測量一次,可以看下它們的源碼;
- 删除控件中無用的屬性;
- 布局複用.比如listView 布局複用
- 盡量避免過度繪制(overdraw),比如:背景經常容易造成過度繪制。由于我們布局設定了背景,同時用到的MaterialDesign的主題會預設給一個背景。這時應該把主題添加的背景去掉;還有移除 XML 中非必須的背景
- 自定義View優化。使用 canvas.clipRect()來幫助系統識别那些可見的區域,隻有在這個區域内才會被繪制。也是避免過度繪制.
- 啟動優化,啟動速度的監控,發現影響啟動速度的問題所在,優化啟動邏輯,提高應用的啟動速度。比如閃屏頁面,合理優化布局,加載邏輯優化,資料準備,這裡後面我會單獨寫一篇文章講如何優化程式的啟動速度及Splash頁面設計,這裡還會講到熱啟動和冷啟動.
- 合理的重新整理機制,盡量減少重新整理次數,盡量避免背景有高的 CPU 線程運作,縮小重新整理區域。
andriod卡頓優化所用到的工具
性能問題并不容易複現,也不好定位,但是真的碰到問題就需要借助相應的的調試工具,下面介紹比較常用的調試工具。
-
1.Profile GPU Rendering
在手機開發者模式下,有一個卡頓檢測工具叫做:Profile GPU Rendering,看圖:
image.png
上圖中的綠線代表16ms,要確定一秒内打到60fps,你需要確定這些幀的每一條線都在綠色的16ms标記線之下.任何時候你看到一個豎線超過了綠色的标記現,你就會看到你的動畫有卡頓現象産生.
下面的柱狀圖藍色代表測量繪制的時間,當你看到藍色的線很高的時候,有可能是因為你的一堆視圖突然變得無效了(即需要重新繪制),或者你的幾個自定義視圖的onDraw函數過于複雜.
柱狀圖紅色代表執行的時間,這部分是Android進行2D渲染 Display List的時間,為了繪制到螢幕上,Android需要使用OpenGl ES的API接口來繪制Display List.這些API有效地将資料發送到GPU,最終在螢幕上顯示出來.當你看到紅色的線非常高的時候,這些複雜的自定義View就是罪魁禍首:
橙色部分表示的是處理時間,或者說是CPU告訴GPU渲染一幀的地方,這是一個阻塞調用,因為CPU會一直等待GPU發出接到指令的回複,如果柱狀圖很高,那就意味着你給GPU太多的工作,太多的負責視圖需要OpenGL指令去繪制和處理.
總之,保持動畫流暢的關鍵就在于讓這些垂直的柱狀條盡可能地保持在綠線下面,任何時候超過綠線,你就有可能丢失一幀的内容.
-
2.Debug GPU overDraw過度繪制檢測
在手機開發者模式下,有一個過度繪制檢測工具叫做:Debug GPU overDraw,看圖:
原色:沒有過度繪制
藍色:1 次過度繪制
綠色:2 次過度繪制
粉色:3 次過度繪制
紅色:4 次及以上過度繪制
耗電優化
在移動裝置中,電池的重要性不言而喻,沒有電什麼都幹不成。對于作業系統和裝置開發商來說,耗電優化一緻沒有停止,去追求更長的待機時間,而對于一款應用來說,并不是可以忽略電量使用問題,特别是那些被歸為“電池殺手”的應用,最終的結果是被解除安裝。是以,應用開發者在實作需求的同時,需要盡量減少電量的消耗。
耗電的原因其實很多,這裡我就講一下幾種優化方案,優化方案的反面就是他的原因了,幾種優化方案如下:
- 合理的使用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 是一款由 Google 提供的 Android 系統電量分析工具,是一款圖形化資料分析工具,直覺地展示出手機的電量消耗過程,通過輸入電量分析檔案,顯示消耗情況,最後提供一些可供參考電量優化的方法。
- Battery Historian耗電分析工具
Battery Historian耗電分析工具的
開源位址;具體如何使用這裡不細講,以後單獨寫文章介紹;
安裝包大小優化
随着功能不斷增加,APP的包肯定不會斷的變大,但應用的安裝包越大,使用者下載下傳的門檻越高,特别是在移動網絡情況下,使用者在下載下傳應用時,對安裝包大小的要求更高,是以,減小安裝包大小可以讓更多使用者願意下載下傳和體驗産品。是以,我們還是要想辦法去如何去優化,盡量減小app的安排包.
APP包優化方案
-
res資源優化
(1)隻使用一套圖檔,使用高分辨率的圖檔。
(2)UI設計在ps安裝
TinyPNG插件,對圖檔進行無損壓縮。
(3)svg圖檔:一些圖檔的描述,犧牲CPU的計算能力的,節省空間。使用的原則:簡單的圖示。
(4)圖檔使用WebP(
https://developers.google.com/speed/webp/)的格式(Facebook、騰訊、淘寶在用。)缺點:加載相比于PNG要慢很多。 但是配置比較高。工具:
http://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 系統中有個垃圾記憶體回收機制,在虛拟機層自動配置設定和釋放記憶體,是以不需要在代碼中配置設定和釋放某一塊記憶體,從應用層面上不容易出現記憶體洩漏和記憶體溢出等問題,但是需要記憶體管理。Android 系統在記憶體管理上有一個 Generational Heap Memory 模型,記憶體回收的大部分壓力不需要應用層關心, Generational Heap Memory 有自己一套管理機制,當記憶體達到一個門檻值時,系統會根據不同的規則自動釋放系統認為可以釋放的記憶體,也正是因為 Android 程式把記憶體控制的權力交給了 Generational Heap Memory,一旦出現記憶體洩漏和溢出方面的問題,排查錯誤将會成為一項異常艱難的工作。除此之外,部分 Android 應用開發人員在開發過程中并沒有特别關注記憶體的合理使用,也沒有在記憶體方面做太多的優化,當應用程式同時運作越來越多的任務,加上越來越複雜的業務需求時,完全依賴 Android 的記憶體管理機制就會導緻一系列性能問題逐漸呈現,對應用的穩定性和性能帶來不可忽視的影響,是以,解決記憶體問題和合理優化記憶體是非常有必要的。
在開發的過程,如果方法不當的話,很容易造成記憶體洩漏,接下來,來說一下哪些情景容易出現記憶體洩漏。
記憶體洩漏出現的情景
- 單例中引用的上下文Context,引用了Activity中的Context, 這樣會造成記憶體洩漏,要引用Application中的Context;
- 資源性對象未關閉。比如Cursor、File檔案等,往往都用了一些緩沖,在不使用時,應該及時關閉它們。
-
注冊對象未登出。比如事件注冊後未登出,會導緻觀察者清單中維持着對象的引用。
類的靜态變量持有大資料對象。
- 非靜态内部類的靜态執行個體。
- Handler臨時性記憶體洩漏。如果Handler是非靜态的,容易導緻 Activity 或 Service 不會被回收。
- 容器中的對象沒清理造成的記憶體洩漏。
- WebView。WebView 存在着記憶體洩漏的問題,在應用中隻要使用一次 WebView,記憶體就不會被釋放掉。
記憶體優化的方案
- 對象引用。強引用、軟引用、弱引用、虛引用四種引用類型,根據業務需求合理使用不同,選擇不同的引用類型。
- 減少不必要的記憶體開銷。注意自動裝箱,增加記憶體複用,比如有效利用系統自帶的資源、視圖複用、對象池、Bitmap對象的複用。
- 使用最優的資料類型。比如針對資料類容器結構,可以使用ArrayMap資料結構,避免使用枚舉類型,使用緩存Lrucache等等。
- 圖檔記憶體優化。可以設定位圖規格,根據采樣因子做壓縮,用一些圖檔緩存方式對圖檔進行管理等等。 圖檔的壓縮幾種方案 ;
記憶體分析工具
做記憶體優化前,需要了解目前應用的記憶體使用現狀,通過現狀去分析哪些資料類型有問題,各種類型的分布情況如何,以及在發現問題後如何發現是哪些具體對象導緻的,這就需要相關工具來幫助我們。以下介紹幾種記憶體分析工具
-
Memory Monitor
Memory Monitor 是一款使用非常簡單的圖形化工具,可以很好地監控系統或應用的記憶體使用情況.
主要有以下功能:
(1).顯示可用和已用記憶體,并且以時間為次元實時反應記憶體配置設定和回收情況。
(2).快速判斷應用程式的運作緩慢是否由于過度的記憶體回收導緻。
(3).快速判斷應用是否由于記憶體不足導緻程式崩潰。
- Heap Viewer
Heap Viewer 的主要功能是檢視不同資料類型在記憶體中的使用情況,可以看到目前程序中的 Heap Size 的情況,分别有哪些類型的資料,以及各種類型資料占比情況。通過分析這些資料來找到大的記憶體對象,再進一步分析這些大對象,進而通過優化減少記憶體開銷,也可以通過資料的變化發現記憶體洩漏。
(1)實時檢視App配置設定的記憶體大小和空閑記憶體大小
(2)發現Memory Leaks
Heap Viewer不光可以用來檢測是否有記憶體洩漏,對于記憶體抖動,我們也可以用該工具檢測,因為記憶體抖動的時候,會頻繁發生GC,這個時候我們隻需要開啟Heap Viewer,觀察資料的變化,如果發生記憶體抖動,會觀察到資料在段時間内頻繁更新。
- Allocation Tracker
Memory Monitor 和 Heap Viewer 都可以很直覺且實時地監控記憶體使用情況,還能發現記憶體問題,但發現記憶體問題後不能再進一步找到原因,或者發現一塊異常記憶體,但不能差別是否正常,同時在發現問題後,也不能定位到具體的類和方法。這時就需要使用另一個記憶體分析工具 Allocation Tracker,進行更詳細的分析, Allocation Tracker 可以配置設定跟蹤記錄應用程式的記憶體配置設定,并列出了它們的調用堆棧,可以檢視所有對象記憶體配置設定的周期。
- Memory Analyzer Tool(MAT)
MAT 是一個快速,功能豐富的 Java Heap 分析工具,通過分析 Java 程序的記憶體快照 HPROF 分析,從衆多的對象中分析,快速計算出在記憶體中對象占用的大小,檢視哪些對象不能被垃圾收集器回收,并可以通過視圖直覺地檢視可能造成這種結果的對象。
穩定性優化
Android 應用的穩定性定義很寬泛,影響穩定性的原因很多,比如記憶體使用不合理、代碼異常場景考慮不周全、代碼邏輯不合理等,都會對應用的穩定性造成影響。其中最常見的兩個場景是:Crash 和 ANR,這兩個錯誤将會使得程式無法使用,比較常用的解決方式如下:
- 提高代碼品質。比如開發期間的代碼稽核,看些代碼設計邏輯,業務合理性等。
- 代碼靜态掃描工具。常見工具有Android Lint、Findbugs、Checkstyle、PMD等等。
- Crash監控。把一些崩潰的資訊,異常資訊及時地記錄下來,以便後續分析解決。
- Crash上傳機制。在Crash後,盡量先儲存日志到本地,然後等下一次網絡正常時再上傳日志資訊。
總結
其實app性能優化,不是一二天可以完成的,主要是要開發的過程,不斷的提前代碼的品質,開發人員提高自己的開發水準,發現了問題,就要及時的解決,好了,這個就寫到這裡,有時間再做補充.