【騰訊Bugly乾貨分享】Android性能優化典範——第6季

来源:http://www.cnblogs.com/bugly/archive/2016/10/24/5992886.html
-Advertisement-
Play Games

這裡是Android性能優化典範第6季的課程學習筆記,從被@知會到有連載更新,這篇學習筆記就一直被惦記著,現在學習記錄分享一下,請多多指教包涵!這次一共才6個小段落,涉及的內容主要有:程式啟動時間性能優化的三個方面:優化activity的創建過程,優化application對象的啟動過程,正確使用啟... ...


本文來自於騰訊bugly開發者社區,非經作者同意,請勿轉載,原文地址:http://dev.qq.com/topic/580d91208d80e49771f0a07c

導語

這裡是Android性能優化典範第6季的課程學習筆記,從被@知會到有連載更新,這篇學習筆記就一直被惦記著,現在學習記錄分享一下,請多多指教包涵!這次一共才6個小段落,涉及的內容主要有:程式啟動時間性能優化的三個方面:優化activity的創建過程,優化application對象的啟動過程,正確使用啟動顯屏達到優化程式啟動性能的目的。另外還介紹了減少安裝包大小的checklist以及如何使用VectorDrawable來減少安裝包的大小。

1. App Launch time 101

提高程式的啟動速度意義重大,很顯然,啟動時間越短,用戶才越有耐心等待打開這個APP進行使用,反之啟動時間越長,用戶則越有可能來不及等到APP打開就已經切換到其他APP了。程式啟動過程中的那些複雜錯誤的操作很可能導致嚴重的性能問題。Android系統會根據用戶的操作行為調整程式的顯示策略,用來提高程式的顯示性能。例如,一旦用戶點擊桌面圖標,Android系統會立即顯示一個啟動視窗,這個視窗會一直保持顯示直到畫面中的元素成功載入並繪製完第一幀。這種行為常見於程式的冷啟動,或者程式的熱啟動場景(程式從後臺被喚起或者從其他APP界面切換回來)。那麼關鍵的問題是,用戶很可能會因為從啟動視窗到顯示畫面的過程耗時過長而感到厭煩,從而導致用戶沒有來得及等程式啟動完畢就切換到其他APP了。更嚴重的是,如果啟動時間過長,可能導致程式出現ANR。我們應該避免出現這兩種糟糕的情況。

從技術角度來說,當用戶點擊桌面圖標開始,系統會立即為這個APP創建獨立的專屬進程,然後顯示啟動視窗,直到APP在自己的進程裡面完成了程式的創建以及主線程完成了Activity的初始化顯示操作,再然後系統進程就會把啟動視窗替換成APP的顯示視窗。

上述流程裡面的絕大多數步驟都是由系統控制的,一般來說不會出現什麼問題,可是對於啟動速度,我們能夠控制並且需要特別關註的地方主要有三處:

  1. Activity的onCreate流程,特別是UI的佈局與渲染操作,如果佈局過於複雜很可能導致嚴重的啟動性能問題。
  2. Application的onCreate流程,對於大型的APP來說,通常會在這裡做大量的通用組件的初始化操作。
  3. 目前有部分APP會提供自定義的啟動視窗,這裡可以做成品牌宣傳界面或者是給用戶提供一種程式已經啟動的視覺效果。

在正式著手解決問題之前,我們需要掌握一套正確測量評估啟動性能的方法。所幸的是,Android系統有提供一些工具來幫助我們定位問題。

  1. 首先是display time:從Android KitKat版本開始,Logcat中會輸出從程式啟動到某個Activity顯示到畫面上所花費的時間。這個方法比較適合測量程式的啟動時間。
  2. 其次是reportFullyDrawn方法:我們通常來說會使用非同步懶載入的方式來提升程式畫面的顯示速度,這通常會導致的一個問題是,程式畫面已經顯示,可是內容卻還在載入中。為了衡量這些非同步載入資源所耗費的時間,我們可以在非同步載入完畢之後調用activity.reportFullyDrawn()方法來告訴系統此時的狀態,以便獲取整個載入的耗時。
  3. 然後是Method Tracing:前面兩個方法提供了啟動耗時的總時間,可是卻無法提供具體的耗時細節。為了獲取具體的耗時分佈情況,我們可以使用Method Tracing工具來進行詳細的測量。
  4. 最後是Systrace:我們可以在onCreate方法裡面添加trace.beginSection()與trace.endSection()方法來聲明需要跟蹤的起止位置,系統會幫忙統計中間經歷過的函數調用耗時,並輸出報表。

2. App Launch Time & Activity Creation

提升Activity的創建速度是優化APP啟動速度的首要關註目標。從桌面點擊APP圖標啟動應用開始,程式會顯示一個啟動視窗等待Activity的創建載入完畢再進行顯示。在Activity的創建載入過程中,會執行很多的操作,例如設置頁面的主題,初始化頁面的佈局,載入圖片,獲取網路數據,讀寫Preference等等。

上述操作的任何一個環節出現性能問題都可能導致畫面不能及時顯示,影響了程式的啟動速度。上一個段落我們介紹了使用Method Tracing來發現那些耗時占比相對較多的方法。假設我們發現某個方法執行時間過長,接下去就可以使用Systrace來幫忙定位到底是什麼原因導致那個方法執行時間過長。

除了使用工具進行具體定位分析性能問題之外,以下兩點經驗可以幫助我們對Activity啟動做性能優化:

  1. 優化佈局耗時:一個佈局層級越深,裡面包含需要載入的元素越多,就會耗費更多的初始化時間。關於佈局性能的優化,這裡就不展開描述了!
  2. 非同步延遲載入:一開始只初始化最需要的佈局,非同步載入圖片,非立即需要的組件可以做延遲載入。

3. App Launch Time & Bloated Application Objects

在Application初始化的地方做太多繁重的事情是可能導致嚴重啟動性能問題的元凶之一。Application裡面的初始化操作不結束,其他任意的程式操作都無法進行。

有時候,我們會一股腦的把絕大多數全局組件的初始化操作都放在Application的onCreate裡面,但其實很多組件是需要做區隊對待的,有些可以做延遲載入,有些可以放到其他的地方做初始化操作,特別需要留意包含Disk IO操作,網路訪問等嚴重耗時的任務,他們會嚴重阻塞程式的啟動。

優化這些問題的解決方案是做延遲載入,可以在application裡面做延遲載入,也可以把一些初始化的操作延遲到組件真正被調用到的時候再做載入。

4. App Launch Time & Theme Launch Screens

啟動閃屏不僅僅可以作為品牌宣傳頁,還能夠減輕用戶對啟動耗時的感知,但是如果使用不恰當,將適得其反。前面介紹過當點擊桌面圖標啟動APP的時候,程式會顯示一個啟動視窗,一直到頁面的渲染載入完畢。如果程式的啟動速度足夠快,我們看的閃屏視窗停留顯示的時間則會很短,但是當程式啟動速度偏慢的時候,這個啟動閃屏可以一定程度上減輕用戶等待的焦慮感,避免用戶過於輕易的關閉應用。

目前大多數開發者都會通過設置啟動視窗主題的方式來替換系統預設的啟動視窗,通過這種方式只是使用『障眼法』弱化了用戶對啟動時間的感知,但本質上並沒有對啟動速度做什麼優化。也有些APP通過關閉啟動視窗屬性android:windowDisablePreview的方式來直接移除系統預設的啟動視窗,但是這樣的弊端是用戶從點擊桌面圖標到真的看到實際頁面的這段時間當中,畫面沒有任何變化,這樣的用戶體驗是十分糟糕的!

對於啟動閃屏,正確的使用方法是自定義一張圖片,把這張圖片通過設置主題的方式顯示為啟動閃屏,代碼執行到主頁面的onCreate的時候設置為程式正常的主題。

5. Smaller APKs: A Checklist

減少應用程式安裝包的大小,不僅僅減少了用戶的網路數據流量還減少了下載等待的時間。毋庸置疑,儘量減少程式安裝包的大小是十分有必要的。通常來說,減少程式安裝包的大小有兩條規律:要麼減少程式資源的大小,要麼就是減少程式的代碼量。這裡總結一個簡易版的減少安裝包大小的Checklist:

減少程式圖片資源的大小

  1. 確保在build.gradle文件中開啟了minifEnabledshrinkResources的屬性,這兩個屬性可以幫助移除那些在程式中使用不到的代碼與資源,幫助減少APP的安裝包大小。
  2. 有選擇性的提供對應解析度的圖片資源,系統會自動匹配最合適解析度的圖片並執行拉伸或者壓縮的處理。
  3. 在符合條件的情況下,使用Vertor Drawable替代傳統的PNG/JPEG圖片,能夠極大的減少圖片資源的大小。傳統模式下,針對不同dpi的手機都需要提供一套PNG/JPEG的圖片,而如果使用Vector Drawable的話,只需要一個XML文件即可。
  4. 儘量復用已經存在的資源圖片,使用代碼的方式對已有的資源進行復用,如下圖所示:

以上幾點雖然看起來都微不足道,但是真正執行之後,能夠顯著減少安裝包的資源圖片大小。

減少程式的代碼量

  1. 開啟MinifEnabled,Proguard。打開這些編譯屬性之後,程式在打包的時候就不會把沒有引用到的代碼編譯進來,以此達到減少安裝包大小的目的。

  2. 註意因為編譯行為額外產生的方法數,例如類似Enum,Protocal Buffer可能導致方法數與類的個數增加。

  3. 部分引入到工程中的jar類庫可能並不是專門針對移動端APP而設計的,他們最開始可能是運用在PC或者Server上的。使用這些類庫不僅僅額外增加了包的大小,還增加了編譯時間。單純依靠Proguard可能無法完全移除那些使用不到的方法,最佳的方式是使用一些更加輕量化,專門為Android APP設計的jar類庫。

安裝包的拆分

設想一下,一個low dpi,API<14的用戶手機下載安裝的APK裡面卻包含了大量xxhdpi的資源文件,對於這個用戶來說,這個APK是存在很大的資源浪費的。幸好Android平臺為我們提供了拆分APK的方法,它能夠根據API Level,屏幕大小以及GPU版本的不同進行拆分,使得對應平臺的用戶下載到最合適自己手機的安裝包。

更多關於安裝包拆分的信息,請查看Configure APK SplitsMaintaining Multiple APKs(由於國內應用分發市場的現狀,這一條幾乎沒有辦法執行)。

6. VectorDrawable for smaller APKs

針對不同的解析度提供多張精度的圖片會額外增加APK的大小,針對這個問題的解決方案是考慮使用VectorDrawable,它僅僅只需要一個文件,能夠動態生成對應解析度的圖片。

VectorDrawable通過XML文件描述圖片的形狀,大小,樣式。

通過這種方式,我們可以顯著減少圖片資源對安裝包大小的影響。

使用VectorDrawable還可以避免因為使用幀動畫導致的圖片資源過多的情況,如下圖所示

前面介紹了VectorDrawable(VD)的優勢,但是在使用VectorDrawable的時候,還是有以下的問題需要特別註意的?

  • 首先VD的載入有異於JPEG/PNG文件,圖片文件可以依靠硬體進行紋理的渲染,而VD文件需要先進行載入解析,然後才能夠進行紋理的渲染。
  • 其次VD文件適用於簡單有規則的圖片渲染,不適用於那些紋理過於複雜的圖片,這樣不僅僅會過度增加描述文件的複雜度還可能無法獲取到想要的渲染效果。
  • 最後VD文件中關於Path的描述需要儘量簡化,複雜冗餘的Path信息不僅對得到想要的圖片沒有益處,還增加了載入渲染的難度。

作者簡介:

胡凱,騰訊 Android 工程師,熱愛開源與分享,維護 Android 官方培訓課程協作項目,關註 Android 應用性能優化的總結與分享,推崇 Android 官方最佳實踐。
個人博客:http://hukai.me
Github:https://github.com/kesenhoo


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • directive裡面的幾個配置,上代碼就清晰了 這段代碼在瀏覽器上打開是這樣的, 看到嗎,directive裡面的template在標簽的裡面,是標簽的子元素 然後再看,在配置一個replace replace為true的時候可以看到的是原來的自定義標簽被template替代了 要是restric ...
  • 這裡多謝某童鞋的提醒!說我的上篇隨筆jquery插件開發的方式一還還可用於合併參數和深clone,雖然方式二中用了方式一做參數合併,但並未詳細介紹,所以今天在此處做點補充! 一、合併參數 jquery的extend擴展原型: 返回值未arg1,arg2……合併到arg。這裡就有兩種用法。 省略arg ...
  • avalon.js是一款迷你的MVVM框架,設計者將其相容到了IE6。輕巧的體積和良好的相容使它非常適合國內的某些項目(學校、政府、銀行)。然而有時候居然出現了在ie上無法渲染的情況。 例如下列這段簡單的demo: 在chrome上的顯示是: 而在ie8上顯示卻是這樣: 大家不要慌張,可能是你加入了 ...
  • 一,JS模塊化演變過程 1.普通函數封裝 最初的這種普通函數封裝的缺點很明顯:污染了全局變數,無法避免的會與其他模塊發生變數名衝突,而且自身模塊成員之間沒有任何聯繫,,說白了就是沒有做到“高內聚,低耦合”原則 2.對象 技術一直在進步,這種做法的避免了變數污染,只要保證模塊名唯一即可,自身模塊內的成 ...
  • 所謂彈性滾動就是指在翻動長頁面手指離開時,有由慢到塊,由快到慢的過度。 安卓平臺上的大多數瀏覽器都預設了該行為 ios當前還只對<body>下的 overflow 預設產生彈性滾動效果 前一陣子做了一個手機官網,用到了 <div> 中的 overflow,再調試 ios 中遇到了彈性滾動的問題: i ...
  • javascript的一切實例都是對象,只是對象之間稍有不同,分為基本類型和引用類型。 基本類型對象指的是字元串(String)、數值(Number)、布爾值(Boolean),引用類型對象指的是數組(Array)、對象(Object)、函數(Function)。 這兩類數據的引用有差別。普通對象存 ...
  • /** * 獲取程式包名(本程式包名5.0版本上下都可獲取) * * @return */ public String getTaskPackname() { ActivityManager.RunningAppProcessInfo currentInfo = null; Field field  ...
  • 蘋果在iOS 10開放了系統電話許可權,全新的Callkit框架能夠讓音視頻的第三方應用獲得系統級的通話體驗,本次分享將主要介紹如何應用Callkit框架和一些適配經驗。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...