1. 程式人生 > >android開發(效能篇)

android開發(效能篇)

今天想說的重點是Android APP效能優化,也就是在開發應用程式時應該注意的點有哪些,如何更好地提高使用者體驗。一個好的應用,除了要有吸引人的功能和互動之外,在效能上也應該有高的要求,即時應用非常具有特色,在產品前期可能吸引了部分使用者,但是使用者體驗不好的話,也會給產品帶來不好的口碑。那麼一個好的應用應該如何定義呢?主要有以下三方面:

  • 業務/功能

  • 符合邏輯的互動

  • 優秀的效能

眾所周知,Android系統作為以移動裝置為主的作業系統,硬體配置是有一定的限制的,雖然配置現在越來越高階,但仍然無法與PC相比,在CPU和記憶體上使用不合理或者耗費資源多時,就會碰到記憶體不足導致的穩定性問題、CPU 消耗太多導致的卡頓問題等。

面對問題時,大家想到的都是聯絡使用者,然後檢視日誌,但殊不知有關效能類問題的反饋,原因也非常難找,日誌大多用處不大,為何呢?因為效能問題大部分是非必現的問題,問題定位很難復現,而又沒有關鍵的日誌,當然就無法找到原因了。這些問題非常影響使用者體驗和功能使用,所以瞭解一些效能優化的一些解決方案就顯得很重要了,並在實際的專案中優化我們的應用,進而提高使用者體驗。

四個方面

可以把使用者體驗的效能問題主要總結為4個類別:

  • 流暢

  • 穩定

  • 省電、省流量

  • 安裝包小

效能問題的主要原因是什麼,原因有相同的,也有不同的,但歸根到底,不外乎記憶體使用、程式碼效率、合適的策略邏輯、程式碼質量、安裝包體積這一類問題,整理歸類如下:

從圖中可以看到,打造一個高質量的應用應該以4個方向為目標:快、穩、省、小。

  • 快:使用時避免出現卡頓,響應速度快,減少使用者等待的時間,滿足使用者期望。

  • 穩:減低 crash 率和 ANR 率,不要在使用者使用過程中崩潰和無響應。

  • 省:節省流量和耗電,減少使用者使用成本,避免使用時導致手機發燙。

  • 小:安裝包小可以降低使用者的安裝成本。

要想達到這4個目標,具體實現是在右邊框裡的問題:卡頓、記憶體使用不合理、程式碼質量差、程式碼邏輯亂、安裝包過大,這些問題也是在開發過程中碰到最多的問題,在實現業務需求同時,也需要考慮到這點,多花時間去思考,如何避免功能完成後再來做優化,不然的話等功能實現後帶來的維護成本會增加。

卡頓優化

Android 應用啟動慢,使用時經常卡頓,是非常影響使用者體驗的,應該儘量避免出現。卡頓的場景有很多,按場景可以分為4類:UI 繪製、應用啟動、頁面跳轉、事件響應,如圖:

這4種卡頓場景的根本原因可以分為兩大類:

  • 介面繪製。主要原因是繪製的層級深、頁面複雜、重新整理不合理,由於這些原因導致卡頓的場景更多出現在UI和啟動後的初始介面以及跳轉到頁面的繪製上。

  • 資料處理。導致這種卡頓場景的原因是資料處理量太大,一般分為三種情況,一是資料在處理UI執行緒,二是資料處理佔用CPU高,導致主執行緒拿不到時間片,三是記憶體增加導致GC頻繁,從而引起卡頓。

引起卡頓的原因很多,但不管怎麼樣的原因和場景,最終都是通過裝置螢幕上顯示來達到使用者,歸根到底就是顯示有問題,所以,要解決卡頓,就要先了解Android系統的顯示原理。

Android系統顯示原理

Android顯示過程可以簡單概括為:Android應用程式把經過測量、佈局、繪製後的Surface快取資料,通過SurfaceFlinger把資料渲染到顯示螢幕上, 通過Android的重新整理機制來重新整理資料。也就是說應用層負責繪製,系統層負責渲染,通過程序間通訊把應用層需要繪製的資料傳遞到系統層服務,系統層服務通過重新整理機制把資料更新到螢幕上。

我們都知道在Android的每個View繪製中有三個核心步驟:Measure、Layout、Draw。具體實現是從 ViewRootImp類的performTraversals() 方法開始執行,Measure和Layout都是通過遞迴來獲取View的大小和位置,並且以深度作為優先順序,可以看出層級越深、元素越多、耗時也就越長。

真正把需要顯示的資料渲染到螢幕上,是通過系統級程序中的SurfaceFlinger服務來實現的,那麼這個SurfaceFlinger服務主要做了哪些工作呢?如下:

  • 響應客戶端事件,建立Layer與客戶端的Surface建立連線。

  • 接收客戶端資料及屬性,修改Layer屬性,如尺寸、顏色、透明度等。

  • 將建立的Layer內容重新整理到螢幕上。

  • 維持Layer的序列,並對Layer最終輸出做出裁剪計算。

既然是兩個不同的程序,那麼肯定是需要一個跨程序的通訊機制來實現資料傳遞,在Android顯示系統中,使用了Android的匿名共享記憶體:SharedClient,每一個應用和SurfaceFlinger之間都會建立一個SharedClient ,然後在每個SharedClient中,最多可以建立31個 SharedBufferStack,每個Surface都對應一個SharedBufferStack,也就是一個Window。

一個SharedClient對應一個Android應用程式,而一個Android應用程式可能包含多個視窗,即Surface。也就是說SharedClient包含的是SharedBufferStack的集合,其中在顯示重新整理機制中用到了雙緩衝和三重緩衝技術。最後總結起來顯示整體流程分為三個模組:應用層繪製到快取區,SurfaceFlinger把快取區資料渲染到螢幕,由於是不同的程序,所以使用Android的匿名共享記憶體SharedClient快取需要顯示的資料來達到目的。

除此之外,我們還需要一個名詞:FPS。FPS表示每秒傳遞的幀數。在理想情況下,60FPS就感覺不到卡,這意味著每個繪製時長應該在16ms以內。但是 Android系統很有可能無法及時完成那些複雜的頁面渲染操作。Android系統每隔16ms發出VSYNC訊號,觸發對UI進行渲染,如果每次渲染都成功,這樣就能夠達到流暢的畫面所需的60FPS。如果某個操作花費的時間是24ms ,系統在得到VSYNC訊號時就無法正常進行正常渲染,這樣就發生了丟幀現象。那麼使用者在32ms內看到的會是同一幀畫面,這種現象在執行動畫或滑動列表比較常見,還有可能是你的Layout太過複雜,層疊太多的繪製單元,無法在16ms完成渲染,最終引起重新整理不及時。

卡頓根本原因

根據Android系統顯示原理可以看到,影響繪製的根本原因有以下兩個方面:

  • 繪製任務太重,繪製一幀內容耗時太長。

  • 主執行緒太忙,根據系統傳遞過來的VSYNC訊號來時還沒準備好資料導致丟幀。

繪製耗時太長,有一些工具可以幫助我們定位問題。主執行緒太忙則需要注意了,主執行緒關鍵職責是處理使用者互動,在螢幕上繪製畫素,並進行載入顯示相關的資料,所以特別需要避免任何主執行緒的事情,這樣應用程式才能保持對使用者操作的即時響應。總結起來,主執行緒主要做以下幾個方面工作:

  • UI生命週期控制

  • 系統事件處理

  • 訊息處理

  • 介面佈局

  • 介面繪製

  • 介面重新整理

除此之外,應該儘量避免將其他處理放在主執行緒中,特別複雜的資料計算和網路請求等。

效能分析工具

效能問題並不容易復現,也不好定位,但是真的碰到問題還是需要去解決的,那麼分析問題和確認問題是否解決,就需要藉助相應的的除錯工具,比如檢視Layout層次的Hierarchy View、Android系統上帶的GPU Profile工具和靜態程式碼檢查工具Lint等,這些工具對效能優化起到非常重要的作用,所以要熟悉,知道在什麼場景用什麼工具來分析。

1,Profile GPU Rendering

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

它的功能特點如下:

  • 一個圖形監測工具,能實時反應當前繪製的耗時

  • 橫軸表示時間,縱軸表示每一幀的耗時

  • 隨著時間推移,從左到右的重新整理呈現

  • 提供一個標準的耗時,如果高於標準耗時,就表示當前這一幀丟失

2,TraceView

TraceView是Android SDK自帶的工具,用來分析函式呼叫過程,可以對Android的應用程式以及Framework層的程式碼進行效能分析。它是一個圖形化的工具,最終會產生一個圖表,用於對效能分析進行說明,可以分析到每一個方法的執行時間,其中可以統計出該方法呼叫次數和遞迴次數,實際時長等引數維度,使用非常直觀,分析效能非常方便。

3,Systrace UI 效能分析

Systrace是Android 4.1及以上版本提供的效能資料取樣和分析工具,它是通過系統的角度來返回一些資訊。它可以幫助開發者收集Android關鍵子系統,如Surfaceflinger、WindowManagerService等Framework部分關鍵模組、服務、View系統等執行資訊,從而幫助開發者更直觀地分析系統瓶頸,改進效能。Systrace的功能包括跟蹤系統的I/O操作、核心工作佇列、CPU負載等,在UI顯示效能分析上提供很好的資料,特別是在動畫播放不流暢、渲染卡等問題上。

優化建議

1,佈局優化

佈局是否合理主要影響的是頁面測量時間的多少,我們知道一個頁面的顯示測量和繪製過程都是通過遞迴來完成的,多叉樹遍歷的時間與樹的高度h有關,其時間複雜度O(h),如果層級太深,每增加一層則會增加更多的頁面顯示時間,所以佈局的合理性就顯得很重要。

那佈局優化有哪些方法呢,主要通過減少層級、減少測量和繪製時間、提高複用性三個方面入手。總結如下:

  • 減少層級。合理使用RelativeLayout和LinerLayout,合理使用Merge。

  • 提高顯示速度。使用ViewStub,它是一個看不見的、不佔佈局位置、佔用資源非常小的檢視物件。

  • 佈局複用。可以通過

    標籤來提高複用。

  • 儘可能少用wrap_content。wrap_content 會增加布局measure時計算成本,在已知寬高為固定值時,不用wrap_content 。

  • 刪除控制元件中無用的屬性。

2,避免過度繪製

過度繪製是指在螢幕上的某個畫素在同一幀的時間內被繪製了多次。在多層次重疊的UI結構中,如果不可見的UI也在做繪製的操作,就會導致某些畫素區域被繪製了多次,從而浪費了多餘的CPU以及GPU源。

如何避免過度繪製呢,如下:

  • 佈局上的優化。移除XML中非必須的背景,移除Window預設的背景、按需顯示佔位背景圖片

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

3,啟動優化

通過對啟動速度的監控,發現影響啟動速度的問題所在,優化啟動邏輯,提高應用的啟動速度。啟動主要完成三件事:UI佈局、繪製和資料準備。因此啟動速度優化就是需要優化這三個過程:

  • UI佈局。應用一般都有閃屏頁,優化閃屏頁的UI佈局,可以通過Profile GPU Rendering檢測丟幀情況。

  • 啟動載入邏輯優化。可以採用分佈載入、非同步載入、延期載入策略來提高應用啟動速度。

  • 資料準備。資料初始化分析,載入資料可以考慮用執行緒初始化等策略。

4,合理的重新整理機制

在應用開發過程中,因為資料的變化,需要重新整理頁面來展示新的資料,但頻繁重新整理會增加資源開銷,並且可能導致卡頓發生,因此,需要一個合理的重新整理機制來提高整體的UI流暢度。合理的重新整理需要注意以下幾點:

  • 儘量減少重新整理次數。

  • 儘量避免後臺有高的CPU執行緒執行。

  • 縮小重新整理區域。

5,其他

在實現動畫效果時,需要根據不同場景選擇合適的動畫框架來實現。有些情況下,可以用硬體加速方式來提供流暢度。

記憶體優化

在Android系統中有個垃圾記憶體回收機制,在虛擬機器層自動分配和釋放記憶體,因此不需要在程式碼中分配和釋放某一塊記憶體,從應用層面上不容易出現記憶體洩漏和記憶體溢位等問題,但是需要記憶體管理。Android系統在記憶體管理上有一個Generational Heap Memory模型,記憶體回收的大部分壓力不需要應用層關心,Generational Heap Memory有自己一套管理機制,當記憶體達到一個閾值時,系統會根據不同的規則自動釋放系統認為可以釋放的記憶體,也正是因為Android程式把記憶體控制的權力交給了Generational Heap Memory,一旦出現記憶體洩漏和溢位方面的問題,排查錯誤將會成為一項異常艱難的工作。除此之外,部分Android應用開發人員在開發過程中並沒有特別關注記憶體的合理使用,也沒有在記憶體方面做太多的優化,當應用程式同時執行越來越多的任務,加上越來越複雜的業務需求時,完全依賴Android的記憶體管理機制就會導致一系列效能問題逐漸呈現,對應用的穩定性和效能帶來不可忽視的影響,因此,解決記憶體問題和合理優化記憶體是非常有必要的。

Android記憶體管理機制

Android應用都是在 Android的虛擬機器上執行,應用 程式的記憶體分配與垃圾回收都是由虛擬機器完成的。在Android系統,虛擬機器有兩種執行模式:Dalvik和ART。

1,Java物件生命週期

一般Java物件在虛擬機器上有7個執行階段:

建立階段->應用階段->不可見階段->不可達階段->收集階段->終結階段->物件空間重新分配階段

2,記憶體分配

在Android系統中,記憶體分配實際上是對堆的分配和釋放。當一個Android程式啟動,應用程序都是從一個叫做Zygote的程序衍生出來,系統啟動 Zygote 程序後,為了啟動一個新的應用程式程序,系統會衍生Zygote程序生成一個新的程序,然後在新的程序中載入並執行應用程式的程式碼。其中,大多數的RAM pages被用來分配給Framework程式碼,同時促使RAM資源能夠在應用所有程序之間共享。

但是為了整個系統的記憶體控制需要,Android系統會為每一個應用程式都設定一個硬性的Dalvik Heap Size最大限制閾值,整個閾值在不同裝置上會因為RAM大小不同而有所差異。如果應用佔用記憶體空間已經接近整個閾值時,再嘗試分配記憶體的話,就很容易引起記憶體溢位的錯誤。

3,記憶體回收機制

我們需要知道的是,在Java中記憶體被分為三個區域:Young Generation(年輕代)、Old Generation(年老代)、Permanent Generation(持久代)。最近分配的物件會存放在Young Generation區域。物件在某個時機觸發GC回收垃圾,而沒有回收的就根據不同規則,有可能被移動到Old Generation,最後累積一定時間在移動到Permanent Generation 區域。系統會根據記憶體中不同的記憶體資料型別分別執行不同的GC操作。GC通過確定物件是否被活動物件引用來確定是否收集物件,進而動態回收無任何引用的物件佔據的記憶體空間。但需要注意的是頻繁的GC會增加應用的卡頓情況,影響應用的流暢性,因此需要儘量減少系統GC行為,以便提高應用的流暢度,減小卡頓發生的概率。

記憶體分析工具

做記憶體優化前,需要了解當前應用的記憶體使用現狀,通過現狀去分析哪些資料型別有問題,各種型別的分佈情況如何,以及在發現問題後如何發現是哪些具體物件導致的,這就需要相關工具來幫助我們。

1,Memory Monitor

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

  • 相關推薦

    android開發效能

    今天想說的重點是Android APP效能優化,也就是在開發應用程式時應該注意的點有哪些,如何更好地提高使用者體驗。一個好的應用,除了要有吸引人的功能和互動之外,在效能上也應該有高的要求,即時應用非常具有特色,在產品前期可能吸引了部分使用者,但是使用者體驗不好的話,也會給產品帶來不好的口碑。那麼一

    Asp.net Web Api開發第二效能:使用Jil提升Json序列化效能

    看了幾篇網上關於各種序列化工具的效能對比,在這裡再貼上下: 我們使用了ASP.NET WEB API來提供RESTfull風格的介面給APP呼叫,預設序列化庫用的是:Newtonsoft.Json 為了進一步提高服務端的效能,有必要將序列化庫進行替換。從上圖可以看出,Ji

    基於TypeScript的FineUIMvc組件式開發開頭

    clas toa 教程 cda 解決 處理 如何 show 文章 了解FineUIMvc的都知道,FineUIMvc中采用了大量的IFrame框架,對於IFrame的優缺點網上也有很多的討論,這裏我要說它的一個優點“有助於隔離代碼邏輯”,這也是FineUIMvc官網對它的描

    python開發第二:初始python

    登陸 文件 windows == del pwd keyword 入門 用c語言實現 erPython的種類: Cpython python的官方版本,使用C語言實現,使用最為廣泛,Cpython實現會將源文件()(py文件)轉換成字節碼文件(pyc文件)然後運行再p

    基於hi-nginx的web開發python——cookie和會話管理

    class status domain 登陸 edi 模板引擎 log 怎麽辦 cache hi-nginx通過redis管理會話。 要開啟管理,需要做三件事。 第一件開啟userid: userid on;

    微信公眾號開發科普

    名詞解釋 接口調用 sdk acc android平臺 調用 解釋 小程序 內容 公眾號分類 一、訂閱號 具有信息發布與傳播的能力,適合個人及媒體註冊二、服務號 具有用戶管理與提供業務服務的能力,適合企業及組織註冊三、企業號 具有實現企業內部溝通與內部協同

    外星人大戰-------------遊戲開發最終

    接下來實現記分系統,實時跟蹤得分,顯示最高得分,當前等級和剩下的飛船 1.記分:這屬於統計資訊類 #-*-coding:GBK-*- #-*-coding:utf-8-*- #跟蹤遊戲統計資訊的類 class GameStats(): def __init__(self,ai_s

    淺談前端移動端頁面開發佈局

    前言的一些碎碎念:最近一直在寫移動端的頁面,不過一直是用的別人造好的輪子,很多時候並沒有想那是為什麼,那是怎麼樣要那麼寫,就跟著別人的文件去了。本以為自己對移動端的那一丟丟理解,結果很多東西都特麼有問題,所以,今天停下了手中的一些東西,來談下移動端的佈局方案吧 內容有些

    使用者故事驅動的敏捷開發規劃

    敏捷開發現在已經不是新鮮事物了,我們都從各種渠道聽到過不同的團隊實施敏捷的勝果,聽的時候覺得很美,回到家就發現那都是別人家的團隊,結合自己的情況一看就發現問題一大堆。就算是最終打算一試,也經常會不知如何開始。這就是我希望編寫這份文件的原因,能夠找到一個遵循的敏捷

    MMO遊戲伺服器從零開發架構

    MMO遊戲伺服器屬於大型多人線上遊戲伺服器,負載,穩定,效率(包括反饋延遲和開發效率)是這種伺服器基本要求。 本人從10年入行至今一直從事MMO遊戲的研發和架構設計工作,對此類伺服器有一些理解和見解。下面分享給想了解遊戲伺服器開發的朋友們。這些是本人這些年來對MMO伺服器架

    微信企業號開發第一

    微信企業號開發--通知系統(第一篇) 如果只是需要一個簡易的通知系統,那麼可以使用 Server醬 /* 配置方便 也比較快捷 */ 代替這些,下面的內容都是自己重複造輪子學習的過程 。 開發起因: 在開發生活中很多需要用到通知到個人的事情,例如某一api接口出現問題、某某大佬更新了部落格前去膜

    物聯網開發基礎-劉洪峰-專題視訊課程

    物聯網開發(基礎篇)—23532人已學習 課程介紹        本課程分為三個系列,本系列是物聯網開發基礎篇,主要就是物聯網開發入門,特別是向準備投身物聯網開發的軟體人員介紹比較基礎的硬體方面的知識,掌握了初步硬體基礎支援,藉助微軟強大的Visual Studio開發工具,

    Canvas 最佳實踐效能

    Canvas 想必前端同學們都不陌生,它是 HTML5 新增的「畫布」元素,允許我們使用 JavaScript 來繪製圖形。目前,所有的主流瀏覽器都支援 Canvas。 Canvas 最常見的用途是渲染動畫。渲染動畫的基本原理,無非是反覆地擦除和重繪。為了動畫的流暢,留給我渲染一幀的時間,只有短短的 1

    2D網路遊戲開發網路

    在前面的章節中,我們實現了一個簡單的聊天室。今天,我們仍然要圍繞這個主題,但採取別的方法,這個方法很有用,應該說是整個網路引擎的關鍵,它就是――RPC(Remote Procedure Calls),翻譯成中文就可以理解成”遠端功能呼叫”。

    床頭筆記之Android開發番外報錯解決

    已有專案時新建專案執行報錯 your project contains error(s),please fix them before running your application 工程上有紅叉,不知道少了什麼,但是工程中卻沒有任何錯誤,執行程式報錯為: Y

    床頭筆記之Android開發番外報錯解決

    問題描述: 在佈局新增控制元件手動新增還是拖的新增,新增edittext後佈局就不好用 總之,Android介面佈局新增EditText元件後介面無法預覽 報錯 Exception raised during rendering: java.lang.Syst

    Android開發之顯示弄懂ppi、dpi、pt、px、dp、dip、sp之間的關係看這一就夠了

    版權申明】非商業目的註明出處可自由轉載 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/85165773 出自:shusheng007 文章目錄 概述 要解決的疑問 概念篇

    Android 開發神器系列工具Android WiFi ADB

                   做為一個多年奮戰在Android 應用開發一線的程式設計師來說,程式除錯的苦是不言而喻的,在過去的很長一段時間裡,我們如果要除錯Android 應用只能通過USB資料線,一頭連著手機,一頭聯著電腦,不敢讓手機離開電腦半步。 、         

    Android 效能監控系列一原理

    歡迎關注微信公眾號:BaronTalk,獲取更多精彩好文! 一. 前言 效能問題是導致 App 使用者流失的罪魁禍首之一,如果使用者在使用我們 App 的時候遇到諸如頁面卡頓、響應速度慢、發熱嚴重、流量電量消耗大等問題的時候,很可能就會解除安

    Mac os x環境配置 Android ndk 開發環境eclipse

    1.請確保安卓環境已經存在 3. 配置 .bash_profile 開啟終端,輸入命令 pico .bash_profile 首先 export PATH=${PATH}:/Users/Malone/Documents/android-ndk-r13b