1. 程式人生 > >Android 系統性能優化(14)---Android效能優化典範

Android 系統性能優化(14)---Android效能優化典範

1)Battery Drain and Networking

對於手機程式,網路操作相對來說是比較耗電的行為。優化網路操作能夠顯著節約電量的消耗。在效能優化第1季裡面有提到過,手機硬體的各個模組的耗電量是不一樣的,其中移動蜂窩模組對電量消耗是比較大的,另外蜂窩模組在不同工作強度下,對電量的消耗也是有差異的。當程式想要執行某個網路請求之前,需要先喚醒裝置,然後傳送資料請求,之後等待返回資料,最後才慢慢進入休眠狀態。這個流程如下圖所示:

android_perf_2_network_request_mode

在上面那個流程中,蜂窩模組的電量消耗差異如下圖所示:

android_perf_2_battery_drain_mode

從圖示中可以看到,啟用瞬間,傳送資料的瞬間,接收資料的瞬間都有很大的電量消耗,所以,我們應該從如何傳遞網路資料以及何時發起網路請求這兩個方面來著手優化。

1.1)何時發起網路請求

首先我們需要區分哪些網路請求是需要及時返回結果的,哪些是可以延遲執行的。例如,使用者主動下拉重新整理列表,這種行為需要立即觸發網路請求,並等待資料返回。但是對於上傳使用者操作的資料,同步程式設定等等行為則屬於可以延遲的行為。我們可以通過Battery Historian這個工具來檢視關於移動蜂窩模組的電量消耗(關於這部分的細節,請點選Android效能優化之電量篇)。在Mobile Radio那一行會顯示蜂窩模組的電量消耗情況,紅色的部分代表模組正在工作,中間的間隔部分代表模組正在休眠狀態,如果看到有一段區間,紅色與間隔頻繁的出現,那就說明這裡有可以優化的行為。如下圖所示:

android_perf_2_battery_mobile_radio

對於上面可以優化的部分,我們可以有針對性的把請求行為捆綁起來,延遲到某個時刻統一發起請求。如下圖所示:

android_perf_2_battery_batch_delay

經過上面的優化之後,我們再回頭使用Battery Historian匯出電量消耗圖,可以看到喚醒狀態與休眠狀態是連續大塊間隔的,這樣的話,總體電量的消耗就會變得更少。

android_perf_2_battery_mobile_radio_2

當然,我們甚至可以把請求的任務延遲到手機網路切換到WiFi,手機處於充電狀態下再執行。在前面的描述過程中,我們會遇到的一個難題是如何把網路請求延遲,並批量進行執行。還好,Android提供了JobScheduler來幫助我們達成這個目標。

1.2)如何傳遞網路資料

關於這部分主要會涉及到Prefetch(預取)與Compressed(壓縮)這兩個技術。對於Prefetch的使用,我們需要預先判斷使用者在此次操作之後,後續零散的請求是否很有可能會馬上被觸發,可以把後面5分鐘有可能會使用到的零散請求都一次集中執行完畢。對於Compressed的使用,在上傳與下載資料之前,使用CPU對資料進行壓縮與解壓,可以很大程度上減少網路傳輸的時間。

想要知道我們的應用程式中網路請求發生的時間,每次請求的資料量等等資訊,可以通過Android Studio中的Networking Traffic Tool來檢視詳細的資料,如下圖所示:

android_perf_2_battery_network_tracking

2)Wear & Sensors

在Android Wear上會大量的使用Sensors來實現某些特殊功能,如何在儘量節約電量的前提下利用好Sensor會是我們需要特別注意的問題。下面會介紹一些在Android Wear上的最佳實踐典範。

儘量減少重新整理請求,例如我們可以在不需要某些資料的時候儘快登出監聽,減小重新整理頻率,對Sensor的資料做批量處理等等。那麼如何做到這些優化呢?

  • 首先我們需要儘量使用Android平臺提供的既有運動資料,而不是自己去實現監聽採集資料,因為大多數Android Watch自身記錄Sensor資料的行為是有經過做電量優化的。
  • 其次在Activity不需要監聽某些Sensor資料的時候需要儘快釋放監聽註冊。
  • 還有我們需要儘量控制更新的頻率,僅僅在需要重新整理顯示資料的時候才觸發獲取最新資料的操作。
  • 另外我們可以針對Sensor的資料做批量處理,待資料累積一定次數或者某個程度的時候才更新到UI上。
  • 最後當Watch與Phone連線起來的時候,可以把某些複雜操作的事情交給Phone來執行,Watch只需要等待返回的結果。

更對關於Sensors的知識,可以點選這裡

3)Smooth Android Wear Animation

Android Material Design風格的應用採用了大量的動畫來進行UI切換,優化動畫的效能不僅能夠提升使用者體驗還可以減少電量的消耗,下面會介紹一些簡單易行的方法。

在Android裡面一個相對操作比較繁重的事情是對Bitmap進行旋轉,縮放,裁剪等等。例如在一個圓形的鐘表圖上,我們把時鐘的指標摳出來當做單獨的圖片進行旋轉會比旋轉一張完整的圓形圖的所形成的幀率要高56%。

android_perf_2_waer_animation

另外儘量減少每次重繪的元素可以極大的提升效能,假如某個鐘錶介面上有很多需要顯示的複雜元件,我們可以把這些元件做拆分處理,例如把背景圖片單獨拎出來設定為一個獨立的View,通過setLayerType()方法使得這個View強制用Hardware來進行渲染。至於介面上哪些元素需要做拆分,他們各自的更新頻率是多少,需要有針對性的單獨討論。

如何使用Systrace等工具來檢視某些View的渲染效能,在前面的章節裡面有提到過,感興趣的可以點選這裡

對於大多數應用中的動畫,我們會使用PropertyAnimation或者ViewAnimation來操作實現,Android系統會自動對這些Animation做一定的優化處理,在Android上面學習到的大多數效能優化的知識同樣也適用於Android Wear。

想要獲取更多關於Android Wear中動畫效果的優化,請點選WatchFace這個範例。

4)Android Wear Data Batching

在Android Training裡面有關於Wear上面如何利用Wearable API與Phone進行溝通協作的課程(詳情請點選這裡)。因為Phone的CPU與電量都比Wear要強大,另外Phone還可以直接接入網路,而Wear要接入網路則相對更加困難,所以我們在開發Wear應用的時候需要儘量做到把複雜的操作交給Phone來執行。例如我們可以讓Phone來獲取天氣資訊,然後把資料返回Wear進行顯示。更進一步,在之前的效能優化課程裡面我們有學習過如何使用JobScheduler來延遲批量處理任務,假設Phone收到來自Wear的其中一個任務是每隔5分鐘檢查一次天氣情況,那麼Phone使用JobScheduler執行檢查天氣任務之後,先判斷這次返回的結果和之前是否有差異,僅僅當天氣發生變化的時候,才有必要把結果通知到Wear,或者僅僅把變化的某一項資料通知給Wear,這樣可以更大程度上減少Wear的電量消耗。

下面我們總結一下如何優化Wear的效能與電量:

  • 僅僅在真正需要重新整理介面的時候才發出請求
  • 儘量把計算複雜操作的任務交給Phone來處理
  • Phone僅僅在資料發生變化的時候才通知到Wear
  • 把零碎的資料請求捆綁一起再進行操作

5)Object Pools

在程式裡面經常會遇到的一個問題是短時間內建立大量的物件,導致記憶體緊張,從而觸發GC導致效能問題。對於這個問題,我們可以使用物件池技術來解決它。通常物件池中的物件可能是bitmaps,views,paints等等。關於物件池的操作原理,不展開述說了,請看下面的圖示:

android_perf_2_object_pool

使用物件池技術有很多好處,它可以避免記憶體抖動,提升效能,但是在使用的時候有一些內容是需要特別注意的。通常情況下,初始化的物件池裡面都是空白的,當使用某個物件的時候先去物件池查詢是否存在,如果不存在則建立這個物件然後加入物件池,但是我們也可以在程式剛啟動的時候就事先為物件池填充一些即將要使用到的資料,這樣可以在需要使用到這些物件的時候提供更快的首次載入速度,這種行為就叫做預分配。使用物件池也有不好的一面,程式設計師需要手動管理這些物件的分配與釋放,所以我們需要慎重地使用這項技術,避免發生物件的記憶體洩漏。為了確保所有的物件能夠正確被釋放,我們需要保證加入物件池的物件和其他外部物件沒有互相引用的關係。

6)To Index or Iterate?

遍歷容器是程式設計裡面一個經常遇到的場景。在Java語言中,使用Iterate是一個比較常見的方法。可是在Android開發團隊中,大家卻儘量避免使用Iterator來執行遍歷操作。下面我們看下在Android上可能用到的三種不同的遍歷方法:

android_perf_2_iterate_1

android_perf_2_iterate_for_loop

android_perf_2_iterate_simple_loop

使用上面三種方式在同一臺手機上,使用相同的資料集做測試,他們的表現效能如下所示:

android_perf_2_iterate_result

從上面可以看到for index的方式有更好的效率,但是因為不同平臺編譯器優化各有差異,我們最好還是針對實際的方法做一下簡單的測量比較好,拿到資料之後,再選擇效率最高的那個方式。

7)The Magic of LRU Cache

這小節我們要討論的是快取演算法,在Android上面最常用的一個快取演算法是LRU(Least Recently Use),關於LRU演算法,不展開述說,用下面一張圖演示下含義:

android_perf_2_lru_mode

LRU Cache的基礎構建用法如下:

android_perf_2_lru_key_value

為了給LRU Cache設定一個比較合理的快取大小值,我們通常是用下面的方法來做界定的:

android_perf_2_lru_size

使用LRU Cache時為了能夠讓Cache知道每個加入的Item的具體大小,我們需要Override下面的方法:

android_perf_2_lru_sizeof

使用LRU Cache能夠顯著提升應用的效能,可是也需要注意LRU Cache中被淘汰物件的回收,否者會引起嚴重的記憶體洩露。

8)Using LINT for Performance Tips

Lint是Android提供的一個靜態掃描應用原始碼並找出其中的潛在問題的一個強大的工具。

android_perf_2_lint_overview

例如,如果我們在onDraw方法裡面執行了new物件的操作,Lint就會提示我們這裡有效能問題,並提出對應的建議方案。Lint已經整合到Android Studio中了,我們可以手動去觸發這個工具,點選工具欄的Analysis -> Inspect Code,觸發之後,Lint會開始工作,並把結果輸出到底部的工具欄,我們可以逐個檢視原因並根據指示做相應的優化修改。

Lint的功能非常強大,他能夠掃描各種問題。當然我們可以通過Android Studio設定找到Lint,對Lint做一些定製化掃描的設定,可以選擇忽略掉那些不想Lint去掃描的選項,我們還可以針對部分掃描內容修改它的提示優先順序。

建議把與記憶體有關的選項中的嚴重程度標記為紅色的Error,對於Layout的效能問題標記為黃色Warning。

9)Hidden Cost of Transparency

這小節會介紹如何減少透明區域對效能的影響。通常來說,對於不透明的View,顯示它只需要渲染一次即可,可是如果這個View設定了alpha值,會至少需要渲染兩次。原因是包含alpha的view需要事先知道混合View的下一層元素是什麼,然後再結合上層的View進行Blend混色處理。

在某些情況下,一個包含alpha的View有可能會觸發改View在HierarchyView上的父View都被額外重繪一次。下面我們看一個例子,下圖演示的ListView中的圖片與二級標題都有設定透明度。

android_perf_2_trans_listview

大多數情況下,螢幕上的元素都是由後向前進行渲染的。在上面的圖示中,會先渲染背景圖(藍,綠,紅),然後渲染人物頭像圖。如果後渲染的元素有設定alpha值,那麼這個元素就會和螢幕上已經渲染好的元素做blend處理。很多時候,我們會給整個View設定alpha的來達到fading的動畫效果,如果我們圖示中的ListView做alpha逐漸減小的處理,我們可以看到ListView上的TextView等等元件會逐漸融合到背景色上。但是在這個過程中,我們無法觀察到它其實已經觸發了額外的繪製任務,我們的目標是讓整個View逐漸透明,可是期間ListView在不停的做Blending的操作,這樣會導致不少效能問題。

如何渲染才能夠得到我們想要的效果呢?我們可以先按照通常的方式把View上的元素按照從後到前的方式繪製出來,但是不直接顯示到螢幕上,而是使用GPU預處理之後,再又GPU渲染到螢幕上,GPU可以對介面上的原始資料直接做旋轉,設定透明度等等操作。使用GPU進行渲染,雖然第一次操作相比起直接繪製到螢幕上更加耗時,可是一旦原始紋理資料生成之後,接下去的操作就比較省時省力。

android_perf_2_trans_hw_layer

如何才能夠讓GPU來渲染某個View呢?我們可以通過setLayerType的方法來指定View應該如何進行渲染,從SDK 16開始,我們還可以使用ViewPropertyAnimator.alpha().withLayer()來指定。如下圖所示:

android_perf_2_trans_setlayertype

另外一個例子是包含陰影區域的View,這種型別的View並不會出現我們前面提到的問題,因為他們並不存在層疊的關係。

android_perf_2_trans_overlap

為了能夠讓渲染器知道這種情況,避免為這種View佔用額外的GPU記憶體空間,我們可以做下面的設定。

android_perf_2_trans_override_lap

通過上面的設定以後,效能可以得到顯著的提升,如下圖所示:

android_perf_2_trans_overlap_compare

10)Avoiding Allocations in onDraw()

我們都知道應該避免在onDraw()方法裡面執行導致記憶體分配的操作,下面講解下為何需要這樣做。

首先onDraw()方法是執行在UI執行緒的,在UI執行緒儘量避免做任何可能影響到效能的操作。雖然分配記憶體的操作並不需要花費太多系統資源,但是這並不意味著是免費無代價的。裝置有一定的重新整理頻率,導致View的onDraw方法會被頻繁的呼叫,如果onDraw方法效率低下,在頻繁重新整理累積的效應下,效率低的問題會被擴大,然後會對效能有嚴重的影響。

android_perf_2_ondraw_gc

如果在onDraw裡面執行記憶體分配的操作,會容易導致記憶體抖動,GC頻繁被觸發,雖然GC後來被改進為執行在另外一個後臺執行緒(GC操作在2.3以前是同步的,之後是併發),可是頻繁的GC的操作還是會影響到CPU,影響到電量的消耗。

那麼簡單解決頻繁分配記憶體的方法就是把分配操作移動到onDraw()方法外面,通常情況下,我們會把onDraw()裡面new Paint的操作移動到外面,如下面所示:

android_perf_2_ondraw_paint

11)Tool: Strict Mode

UI執行緒被阻塞超過5秒,就會出現ANR,這太糟糕了。防止程式出現ANR是很重要的事情,那麼如何找出程式裡面潛在的坑,預防ANR呢?很多大部分情況下執行很快的方法,但是他們有可能存在巨大的隱患,這些隱患的爆發就很容易導致ANR。

Android提供了一個叫做Strict Mode的工具,我們可以通過手機設定裡面的開發者選項,開啟Strict Mode選項,如果程式存在潛在的隱患,螢幕就會閃現紅色。我們也可以通過StrictMode API在程式碼層面做細化的跟蹤,可以設定StrictMode監聽那些潛在問題,出現問題時如何提醒開發者,可以對螢幕閃紅色,也可以輸出錯誤日誌。下面是官方的程式碼示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void onCreate() {
     if (DEVELOPER_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyLog()
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects()
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
     }
     super.onCreate();
}

12)Custom Views and Performance

Android系統有提供超過70多種標準的View,例如TextView,ImageView,Button等等。在某些時候,這些標準的View無法滿足我們的需要,那麼就需要我們自己來實現一個View,這節會介紹如何優化自定義View的效能。

相關推薦

Android 系統性優化(14)---Android效能優化典範

1)Battery Drain and Networking對於手機程式,網路操作相對來說是比較耗電的行為。優化網路操作能夠顯著節約電量的消耗。在效能優化第1季裡面有提到過,手機硬體的各個模組的耗電量是不一樣的,其中移動蜂窩模組對電量消耗是比較大的,另外蜂窩模組在不同工作強度

Android 系統性優化(11)---UC效能優化方案

       一、效能優化六項指標:              效能、記憶體、穩定性、流量、電量、安裝包大小;       二、背景 ---- Android程式卡頓產生原因:              1、Android系統低效              --渲染執行緒、同步介面、廣播機制         

Android 系統性優化(36)---顯示效能指標

    從 Android 誕生的那一刻起,流暢度就為眾人所關注。一時之間,似乎所有人都在討論 Android 和 iOS 誰的流暢度更好。但是,毫不誇張的說,流暢度絕對是 Android 眾多效能維度中最為奇葩的一個。因為,為了刻畫這一效能維度,業界設計了各式各樣的指標來對

Android 系統性優化(52)---移動端效能監控方案Hertz

效能問題是造成App使用者流失的罪魁禍首之一。App的效能問題包括崩潰、網路請求錯誤或超時、響應速度慢、列表滾動卡頓、流量大、耗電等等。而導致App效能低下的原因有很多,除去裝置硬體和軟體的外部因素,其中大部分是開發者錯誤地使用執行緒、鎖、系統函式、程式設計正規化、資料結構等導致的。即便是最有經驗的程式設計師

Android 系統性優化(34)---Android UI 效能優化

Android官網 Slow rendering;個人覺得非常有價值,比如指出 物件分配、垃圾回收(GC)、執行緒排程以及Binder呼叫 是Android系統中常見的卡頓原因,更重要的是給出了定位和解決這些問題的方案;而非簡單地告訴你避免物件分配,減少佈局層級,減少過度

Android 系統性優化(28)---Android 效能優化工具集合

磁碟檔案讀寫:每次開啟、關閉或者讀寫檔案,作業系統都需要經過從使用者態轉換為核心態的切換,這種狀態的切換本身是很消耗效能的,所以為了提高檔案的讀寫效率,就需要儘量減少使用者態和核心態的切換。使用快取可以避免重複讀寫,對於需要多次訪問的資料,在第一次取出資料的時候,將資料放在快

Android 系統性優化(30)---Android效能全面分析與優化方案研究

5.1、渲染問題先來看看造成應用UI卡頓的常見原因都有哪些?1、人為在UI執行緒中做輕微耗時操作,導致UI執行緒卡頓;2、佈局Layout過於複雜,無法在16ms內完成渲染;3、同一時間動畫執行的次數過多,導致CPU或GPU負載過重;4、View過度繪製,導致某些畫素在同一幀時間內被繪製多次,從而使CPU或G

android系統性優化(63)---Android APP 卡頓問題分析及解決方案

使用者對卡頓的感知, 主要來源於介面的重新整理. 而介面的效能主要是依賴於裝置的UI渲染效能. 如果我們的UI設計過於複雜, 或是實現不夠友好,計算繪製演算法不夠優化, 裝置又不給力, 介面就會像卡住了一樣, 給使用者卡頓的感覺.如果你的應用介面出現卡頓不流暢的情況,不用懷疑,這很大原因是你沒有在16ms完成

Android 系統性優化(16)--Android 系統性優化第4季

1)Cachematters for networking想要使得Android系統上的網路訪問操作更加的高效就必須做好網路資料的快取。這是提高網路訪問效能最基礎的步驟之一。從手機的快取中直接讀取資料肯定比從網路上獲取資料要更加的便捷高效,特別是對於那些會被頻繁訪問到的資料,

Android系統性優化(64)---build.設定

1. 強制把Home程式駐入記憶體.引數:ro.HOME_APP_ADJ=12.提高 JPG 質量為 100%引數:ro.media.enc.jpeg.quality=1003. VM 虛擬堆大小; 提高 RAM引數:dalvik.vm.heapsize=48m4. 使用 GPU 渲染UI引數:debug.s

Android系統性優化(44)---全面&詳細的記憶體優化指南

前言在 Android開發中,效能優化策略十分重要本文主要講解效能優化中的記憶體優化,希望你們會喜歡目錄1. 定義優化處理 應用程式的記憶體使用、空間佔用2. 作用避免因不正確使用記憶體 & 缺乏管理,從而出現 記憶體洩露(ML)、記憶體溢位(OOM)、記憶體空間佔用

Android中Sqlite的使用及效能優化

使用 可以使用安卓原生的工具類: SQLiteOpenHelper 抽象類:通過從此類繼承實現使用者類,來提供資料庫開啟、關閉等操作函式。 SQLiteDatabase 資料庫訪問類:執行對資料庫的插入記錄、查詢記錄等操作。 SQLiteCursor 查詢結構操作類:用來訪問查詢結果中的記錄

QQ音樂Android客戶端Web頁面通用效能優化實踐

QQ音樂 Android 客戶端的 Web 頁面日均 PV 達到千萬量級,然而頁面的開啟耗時與 Native 頁面相距甚遠,需要系統性優化。本文將介紹 QQ 音樂 Android 客戶端在進行 Web 頁面通用效能優化過程中的問題、思路、方案和效果,並嘗試對跨端場景的常見瓶頸和對策進行歸納。文章作者:關岳,

Android系統性調優工具介紹

經作者授權,發表Tieto某青年牛的一篇《程式設計師》大作。Android系統性能調優工具介紹在軟體開發過程中,想必很多讀者都遇到過系統性能問題。而解決系統性能問題的幾個主要步驟是:測評:對系統進行大量

android系統性分析

作為一名Linux 或 Android 平臺的系統工程師,在開發系統新功能外,主要工作就是優化系統性能,使系統上以最優的狀態執行,但是由於硬體問題、軟體問題、網路環境等的複雜性和多變性,導致對系統的優化變得異常複雜,如何定位效能問題出在哪個方面,是效能優化的一大難題, 從系統入手,闡述由於系統軟、硬體配置不當

前端開發的優化問題(看雅虎 14效能優化原則)

(1) 減少 http 請求次數:CSS Sprites, JS、CSS 原始碼壓縮、圖片大小控制合適;網頁Gzip,CDN 託管,data 快取 ,圖片伺服器。 (2)前端模板 JS+資料,減少由於 HTML 標籤導致的頻寬浪費,前端用變數儲存 AJAX請求結果,每次操作

Linux 和 Android 系統性分析

作為一名Linux 或 Android 平臺的系統工程師,在開發系統新功能外,主要工作就是優化系統性能,使系統上以最優的狀態執行,但是由於硬體問題、軟體問題、網路環境等的複雜性和多變性,導致對系統的優化變得異常複雜,如何定位效能問題出在哪個方面,是效能優化的一大難題, 從系

Mysql資料庫效能優化之查詢效能優化

一、前言:為啥查詢速度會變慢? 通常來說,查詢的生命週期大致分為從客戶端、到伺服器,然後在伺服器上進行解析,生成執行計劃,執行,並返回結果給客戶端。其中執行可以說是最重要的階段,這其中包括了大量為了檢索資料到儲存引擎的呼叫以及呼叫後的資料處理,包括排序和分組等。在每一個消耗大量時間的查

Hbase常用優化、Hbae效能優化、Hbase優化經驗總結

Hbase優化 1.預先分割槽 預設情況下,在建立 HBase 表的時候會自動建立一個 Region 分割槽,當匯入資料的時候,所有的 HBase 客戶端都向這一個 Region 寫資料,直到這個 Region 足夠大了才進行切分。一種可以加快批量寫入速度的方法是通過預先建立一些空的 Reg

軟考-架構師-第五章-系統性評價 第二節 效能計算(讀書筆記)

主要針對希賽出版的架構師考試教程《系統架構設計師教程(第4版)》,作者“希賽教育軟考學院”。完成相關的讀書筆記以便後期自查,僅供個人學習使用,不得用於任何商業用途。 第二節 效能計算 效能指標計算方法 定義法 定義法主要根據其定義直接獲取其理想資料。 公式法