Android:史上最全性能優(yōu)化方案解析
Android中的性能優(yōu)分為以下幾個(gè)方面:
布局優(yōu)化
內(nèi)存優(yōu)化
卡頓優(yōu)化
……
在LinearLayout和RelativeLayout都可以完成布局的情況下優(yōu)先選擇LinearLayout,可以減少View的層級(jí),但是注意相同組件可能RelativeLayout繪制時(shí)間長
使用 < include > 標(biāo)簽將常用的布局組件共同的部分抽取出來,以便復(fù)用。
通過 < ViewStub > 標(biāo)簽來加載不常用的布局,延遲加載(需要的時(shí)候在activity中加載出來)
使用 < Merge > 標(biāo)簽來減少布局的嵌套層次
二.繪制優(yōu)化
繪制優(yōu)化是指View的onDraw方法要避免執(zhí)行大量的操作,這主要體現(xiàn)在兩個(gè)方面:
1.onDraw中不要?jiǎng)?chuàng)建新的局部對(duì)象。
因?yàn)閛nDraw方法可能會(huì)被頻繁調(diào)用,這樣就會(huì)在一瞬間產(chǎn)生大量的臨時(shí)對(duì)象,這不僅占用了過多的內(nèi)存而且還會(huì)導(dǎo)致系統(tǒng)更加頻繁gc,降低了程序的執(zhí)行效率。
2.onDraw方法中不要做耗時(shí)的任務(wù),
不能執(zhí)行成千上萬次的循環(huán)操作,盡管每次循環(huán)都很輕量級(jí),但是大量的循環(huán)仍然十分搶占CPU的時(shí)間片,這會(huì)造成View的繪制過程不流暢。
按照Google官方給出的性能優(yōu)化典范中的標(biāo)準(zhǔn),View的繪制頻率保證60fps是最佳的,這就要求每幀繪制時(shí)間不超過16ms(16ms = 1000/60),雖然程序很難保證16ms這個(gè)時(shí)間,但是盡量降低onDraw方法中的復(fù)雜度總是切實(shí)有效的。
三.網(wǎng)絡(luò)優(yōu)化
常見的網(wǎng)絡(luò)優(yōu)化方案如下:
盡量減少網(wǎng)絡(luò)請(qǐng)求,能夠合并的就盡量合并
避免DNS解析,根據(jù)域名查詢可能會(huì)耗費(fèi)上百毫秒的時(shí)間,也可能存在DNS劫持的風(fēng)險(xiǎn)??梢愿鶕?jù)業(yè)務(wù)需求采用增加動(dòng)態(tài)更新IP的方式,或者在IP方式訪問失敗時(shí)切換到域名訪問方式。
大量數(shù)據(jù)的加載采用分頁的方式
網(wǎng)絡(luò)數(shù)據(jù)傳輸采用GZIP壓縮
加入網(wǎng)絡(luò)數(shù)據(jù)的緩存,避免頻繁請(qǐng)求網(wǎng)絡(luò)
上傳圖片時(shí),在必要的時(shí)候壓縮圖片
四.安裝包優(yōu)化
安裝包優(yōu)化的核心就是減少apk的體積,常見的方案如下:
減少應(yīng)用中不必要的資源文件,比如圖片,在不影響APP效果的情況下盡量壓縮圖片,有一定的效果
在使用了SO庫的時(shí)候優(yōu)先保留v7版本的SO庫,刪掉其他版本的SO庫。原因是在2018年,v7版本的SO庫可以滿足市面上絕大多數(shù)的要求,可能八九年前的手機(jī)滿足不了,但我們也沒必要去適配老掉牙的手機(jī)。實(shí)際開發(fā)中減少apk體積的效果是十分顯著的,如果你使用了很多SO庫,比方說一個(gè)版本的SO庫一共10M,那么只保留v7版本,刪掉armeabi和v8版本的SO庫,一共可以減少20M的體積。
res資源優(yōu)化
(1)只使用一套圖片,使用高分辨率的圖片。
(2)UI設(shè)計(jì)在ps安裝TinyPNG插件,對(duì)圖片進(jìn)行無損壓縮。
(3)svg圖片:一些圖片的描述,犧牲CPU的計(jì)算能力的,節(jié)省空間。使用的原則:簡單的圖標(biāo)。
(4)圖片使用WebP(https://developers.google.com/speed/webp/)的格式(Facebook、騰訊、淘寶在用。)缺點(diǎn):加載相比于PNG要慢很多。但是配置比較高。工具:http://isparta.github.io/
(5)使用tintcolor(android - Change drawable color programmatically)實(shí)現(xiàn)按鈕反選效果。
代碼優(yōu)化
(1)實(shí)現(xiàn)功能模塊的邏輯簡化
(2)Lint工具檢查無用文件將無用的資源列在“UnusedResources: Unused resources”,刪除。
(3)移除無用的依賴庫。
lib資源優(yōu)化
(1)動(dòng)態(tài)下載的資源。
(2)一些模塊的插件化動(dòng)態(tài)添加。
(3)so文件的剪裁和壓縮。
assets資源優(yōu)化
(1)音頻文件最好使用有損壓縮的格式,比如采用opus、mp3等格式,但是最好不要使用無損壓縮的音樂格式
(2)對(duì)ttf字體文件壓縮,可以采用FontCreator工具只提取出你需要的文字。比如在做日期顯示時(shí),其實(shí)只需要數(shù)字字體,但是使用原有的字體庫可能需要10MB大小,如果只是把你需要的字體提取出來生成的字體文件只有10KB
代碼混淆。
使用proGuard 代碼混淆器工具,它包括壓縮、優(yōu)化、混淆等功能。
插件化
可將功能模塊放服務(wù)器,需要用時(shí)再加載。
7z極限壓縮
五.Android內(nèi)存優(yōu)化
1.Android內(nèi)存管理機(jī)制
Android應(yīng)用都是在Android虛擬機(jī)上運(yùn)行的,內(nèi)存分配和垃圾回收都是由Android虛擬機(jī)來完成的。
2.常見的內(nèi)存泄漏
其實(shí)內(nèi)存泄漏的本質(zhì)就是較長生命周期的對(duì)象引用了較短生命周期的對(duì)象。
2.1 內(nèi)存泄露
內(nèi)存泄漏原因:堆上分配的對(duì)象已經(jīng)不會(huì)再使用,但是GC收集器無法對(duì)其進(jìn)行回收,此對(duì)象被強(qiáng)應(yīng)用所引用 。
靜態(tài)變量導(dǎo)致的內(nèi)存泄漏
解決辦法:將內(nèi)部類設(shè)為靜態(tài)內(nèi)部類或獨(dú)立出來;使用context.getApplicationContext()。
單例模式導(dǎo)致的內(nèi)存泄漏
解決辦法:傳參context.getApplicationContext()。
屬性動(dòng)畫導(dǎo)致的內(nèi)存泄漏
解決辦法:在Activity.onDestroy()中調(diào)用Animator.cancel()停止動(dòng)畫。
Handler導(dǎo)致的內(nèi)存泄漏
解決辦法:使用靜態(tài)內(nèi)部類+WeakReference弱引用;當(dāng)外部類結(jié)束生命周期時(shí)清空消息隊(duì)列。
線程導(dǎo)致的內(nèi)存泄漏
解決辦法:將AsyncTask和Runnable設(shè)為靜態(tài)內(nèi)部類或獨(dú)立出來;在線程內(nèi)部采用弱引用保存Context引用。
資源未關(guān)閉導(dǎo)致的內(nèi)存泄漏
解決辦法:在Activity銷毀的時(shí)候要及時(shí)關(guān)閉或者注銷。例如:
① BraodcastReceiver:調(diào)用unregisterReceiver()注銷;
②Cursor,Stream、File:調(diào)用close()關(guān)閉;
③Bitmap:調(diào)用recycle()釋放內(nèi)存(2.3版本后無需手動(dòng))。
Adapter導(dǎo)致的內(nèi)存泄漏
詳情:不使用緩存而只依靠getView() 每次重新實(shí)例化Item,會(huì)給gc制造壓力。
解決辦法:在構(gòu)造Adapter時(shí)使用緩存的convertView。
WebView導(dǎo)致的內(nèi)存泄漏。
詳情:WebView比較特殊,即使是調(diào)用了它的destroy方法,依然會(huì)導(dǎo)致內(nèi)存泄漏。
解決辦法:其實(shí)避免WebView導(dǎo)致內(nèi)存泄漏的最好方法就是讓W(xué)ebView所在的Activity處于另一個(gè)進(jìn)程中,當(dāng)這個(gè)Activity結(jié)束時(shí)殺死當(dāng)前WebView所處的進(jìn)程即可,我記得阿里釘釘?shù)腤ebView就是另外開啟的一個(gè)進(jìn)程,應(yīng)該也是采用這種方法避免內(nèi)存泄漏。
集合類泄漏
詳情:比如全局map等有靜態(tài)應(yīng)用,最后沒有做刪除。
解決辦法:在onDestry時(shí)回收不需要的集合。
2.2 擴(kuò)大內(nèi)存
大廠的SDK可能內(nèi)存泄漏會(huì)少一些,但一些小廠的SDK質(zhì)量也就不太靠譜一些。那應(yīng)對(duì)這種我們無法改變的情況,最好的辦法就是擴(kuò)大內(nèi)存。
擴(kuò)大內(nèi)存通常有兩種方法:
一個(gè)是在清單文件中的Application下添加largeHeap="true"這個(gè)屬性,另一個(gè)就是同一個(gè)應(yīng)用開啟多個(gè)進(jìn)程來擴(kuò)大一個(gè)應(yīng)用的總內(nèi)存空間。
第二種方法其實(shí)就很常見了,比方說我使用過個(gè)推的SDK,個(gè)推的Service其實(shí)就是處在另外一個(gè)單獨(dú)的進(jìn)程中。
Android中的內(nèi)存優(yōu)化總的來說就是開源和節(jié)流,開源就是擴(kuò)大內(nèi)存,節(jié)流就是避免內(nèi)存泄漏。
2.3 檢測(cè)、分析內(nèi)存泄漏的工具
MemoryMonitor:隨時(shí)間變化,內(nèi)存占用的變化情況
MAT:輸入HRPOF文件,輸出分析結(jié)果
a. Histogram:查看不同類型對(duì)象及其大小
b.DominateTree:對(duì)象占用內(nèi)存及其引用關(guān)系
c.MAT使用教程
LeakCanary:實(shí)時(shí)監(jiān)測(cè)內(nèi)存泄漏的庫(LeakCanary原理)
六.卡頓優(yōu)化方案
不要在主線程進(jìn)行網(wǎng)絡(luò)訪問/大文件的IO操作
繪制UI時(shí),盡量減少繪制UI層次;減少不必要的view嵌套,可以用Hierarchy Viewer工具來檢測(cè),后面會(huì)詳細(xì)講;
當(dāng)我們的布局是用的FrameLayout的時(shí)候,我們可以把它改成merge,可以避免自己的幀布局和系統(tǒng)的ContentFrameLayout幀布局重疊造成重復(fù)計(jì)算(measure和layout)
提高顯示速度,使用ViewStub:當(dāng)加載的時(shí)候才會(huì)占用。不加載的時(shí)候就是隱藏的,僅僅占用位置。
在view層級(jí)相同的情況下,盡量使用 LinerLayout而不是RelativeLayout;因?yàn)镽elativeLayout在測(cè)量的時(shí)候會(huì)測(cè)量二次,而LinerLayout測(cè)量一次,可以看下它們的源碼;
刪除控件中無用的屬性;
布局復(fù)用.比如listView 布局復(fù)用
盡量避免過度繪制(overdraw),比如:背景經(jīng)常容易造成過度繪制。由于我們布局設(shè)置了背景,同時(shí)用到的MaterialDesign的主題會(huì)默認(rèn)給一個(gè)背景。這時(shí)應(yīng)該把主題添加的背景去掉;還有移除
XML 中非必須的背景
自定義View優(yōu)化。使用 canvas.clipRect()來幫助系統(tǒng)識(shí)別那些可見的區(qū)域,只有在這個(gè)區(qū)域內(nèi)才會(huì)被繪制。也是避免過度繪制.
啟動(dòng)優(yōu)化,啟動(dòng)速度的監(jiān)控,發(fā)現(xiàn)影響啟動(dòng)速度的問題所在,優(yōu)化啟動(dòng)邏輯,提高應(yīng)用的啟動(dòng)速度。比如閃屏頁面,合理優(yōu)化布局,加載邏輯優(yōu)化,數(shù)據(jù)準(zhǔn)備.
合理的刷新機(jī)制,盡量減少刷新次數(shù),盡量避免后臺(tái)有高的 CPU 線程運(yùn)行,縮小刷新區(qū)域。
七.耗電優(yōu)化
耗電的原因其實(shí)很多,這里我就講一下幾種優(yōu)化方案,優(yōu)化方案的反面就是他的原因了,幾種優(yōu)化方案如下:
合理的使用wake_lock鎖,wake_lock鎖主要是相對(duì)系統(tǒng)的休眠(這里就是為了省電,才做休)而言的,意思就是我的程序給CPU加了這個(gè)鎖那系統(tǒng)就不會(huì)休眠了,這樣做的目的是為了全力配合我們程序的運(yùn)行。有的情況如果不這么做就會(huì)出現(xiàn)一些問題,比如微信等及時(shí)通訊的心跳包會(huì)在熄屏不久后停止網(wǎng)絡(luò)訪問等問題。所以微信里面是有大量使用到了wake_lock鎖。
使用jobScheduler2,集中處理一些網(wǎng)絡(luò)請(qǐng)求,有些不用很及時(shí)的處理可以放在充電的時(shí)候處理,比如,圖片的處理,APP下載更新等等;
計(jì)算優(yōu)化,避開浮點(diǎn)運(yùn)算等。
數(shù)據(jù)在網(wǎng)絡(luò)上傳輸時(shí),盡量壓縮數(shù)據(jù)后再傳輸,建議用FlatBuffer序列化技術(shù),這個(gè)比json效率高很多倍,不了解FlatBuffer,建議找資料學(xué)習(xí)一下。
針對(duì)“性能優(yōu)化”這個(gè)要點(diǎn),分享給大家一份《360°全方位Android性能優(yōu)化解析》,這份學(xué)習(xí)手冊(cè)將會(huì)帶領(lǐng)大家一步一步深入探索Android的性能優(yōu)化,讓產(chǎn)品的性能從各個(gè)方面得到提升,希望大家喜歡。
這份資料一共有721頁,4個(gè)大點(diǎn),25個(gè)小章節(jié),不僅僅有詳細(xì)的底層原理的解析,還有專門的實(shí)踐案例!
掃碼即可領(lǐng)取資料
第一章 設(shè)計(jì)思想與代碼質(zhì)量優(yōu)化
1.六大原則
單一職責(zé)原則
里氏替換原則
依賴倒轉(zhuǎn)原則
接口隔離原則
……
2.設(shè)計(jì)模式
結(jié)構(gòu)型模式:橋接模式、適配器模式、裝飾器模式、代理模式、門面(外觀)模式……
創(chuàng)建型模式:建造者模式、單例模式、抽象工廠模式、工廠方法模式……
數(shù)據(jù)結(jié)構(gòu):數(shù)組、棧、隊(duì)列、鏈表、樹……
算法:排序算法、查找算法……
第二章 程序性能優(yōu)化
1.啟動(dòng)速度與執(zhí)行效率優(yōu)化
冷啟動(dòng)和熱啟動(dòng)解析
APP 啟動(dòng)黑白屏解決辦法
APP 卡頓問題分析及解決方案
啟動(dòng)速度與執(zhí)行效率優(yōu)化之 StrictMode
……
2.布局檢測(cè)與優(yōu)化
布局層級(jí)優(yōu)化
過度渲染
……
3.內(nèi)存優(yōu)化
內(nèi)存抖動(dòng)和內(nèi)存泄漏
內(nèi)存大戶
Bitmap 內(nèi)存優(yōu)化
Profile 內(nèi)存監(jiān)測(cè)工具
Mat 大對(duì)象與泄漏檢測(cè)
耗電優(yōu)化
網(wǎng)絡(luò)傳輸與數(shù)據(jù)存儲(chǔ)優(yōu)化網(wǎng)絡(luò)傳輸與數(shù)據(jù)存儲(chǔ)優(yōu)化
APK 大小優(yōu)化
屏幕適配
……
4.耗電優(yōu)化
Doze&Standby
Battery Historian
JobScheduler
WorkManager
5.網(wǎng)絡(luò)傳輸與數(shù)據(jù)存儲(chǔ)優(yōu)化
google 序列化工具 protobuf
7z 極限壓縮
……
6.APK 大小優(yōu)化
APK 瘦身
微信資源混淆原理
……
7.屏幕適配
進(jìn)行適配的原理
屏幕分辨率限定符與 smallestWidth 限定符適配原理
為什么選擇 smallestWidth 限定符適配
怎么適配其他 module
常見問題處理
……
8.OOM 問題原理解析
adj 內(nèi)存管理機(jī)制
JVM 內(nèi)存回收機(jī)制與 GC 算法解析
生命周期相關(guān)問題總結(jié)
Bitmap 壓縮方案總結(jié)
……
9.ANR 問題解析
AMS 系統(tǒng)時(shí)間調(diào)節(jié)原理
程序等待原理分析
ANR 問題解決方案
……
10.Crash 監(jiān)控方案
Java 層監(jiān)控方案
Nativie 層監(jiān)控方案
……
第三章 開發(fā)效率優(yōu)化
分布式版本控制系統(tǒng) Git
企業(yè)高效持續(xù)集成平臺(tái)場(chǎng)景介紹
GIT 分布式版本控制系統(tǒng)
GIT 分支管理
……
2.自動(dòng)化構(gòu)建系統(tǒng) Gradle:
Gradle 與 Android 插件:gradle 與 android gradle 插件的關(guān)系、Gradle Transform API 的基本使用……
Gradle Transform API 的基本使用:什么是 Transform、Transform 的使用場(chǎng)景、Transform API 學(xué)習(xí)、輸入的類型……
自定義插件開發(fā):Gradle 插件簡介、開始準(zhǔn)備、實(shí)踐、自定義 Gradle 插件、buildSrc 模塊方式……
插件實(shí)戰(zhàn):多渠道打包、發(fā)版自動(dòng)釘釘……
掃碼即可領(lǐng)取資料
第四章 APP 性能優(yōu)化實(shí)踐
1.啟動(dòng)速度
應(yīng)用啟動(dòng)的一般流程
冷啟動(dòng)和熱啟動(dòng)
啟動(dòng)速度的測(cè)量
啟動(dòng)窗口優(yōu)化
線程優(yōu)化
系統(tǒng)調(diào)度優(yōu)化
GC 優(yōu)化
IO 優(yōu)化
資源重排
主頁布局優(yōu)化
類加載優(yōu)化
選擇合適的啟動(dòng)框架
減少 Activity 的跳轉(zhuǎn)層次
廠商優(yōu)化
后臺(tái)?;?/p>
……

2.流暢度
性能問題分析的一些工具和套路
通過性能數(shù)據(jù)數(shù)據(jù)分析
Android 平臺(tái)性能導(dǎo)致的性能案例
Android App 自身導(dǎo)致的性能問題
低內(nèi)存的數(shù)據(jù)特征和行為特征
應(yīng)用寶
訊飛輸入法無障礙服務(wù)導(dǎo)致的整機(jī)卡頓分析
字節(jié)跳動(dòng):今日頭條圖文詳情頁秒開實(shí)踐
……
3.抖音在 APK 包大小資源優(yōu)化的實(shí)踐
圖片壓縮
webp 無侵入式兼容
多 DPI 優(yōu)化
重復(fù)資源合并
shrinkResource 嚴(yán)格模式
資源混淆(兼容 aab 模式)
ARSC 瘦身
……
4.優(yōu)酷響應(yīng)式布局技術(shù)全解析
優(yōu)酷APP響應(yīng)式布局技術(shù)概述
優(yōu)酷APP響應(yīng)式布局Android落地
在分發(fā)場(chǎng)景的落地
在消費(fèi)場(chǎng)景的落地
優(yōu)酷APP響應(yīng)式布局之測(cè)試方案
……
5.網(wǎng)絡(luò)優(yōu)化
手機(jī)淘寶在網(wǎng)絡(luò)的鏈路優(yōu)化
百度 APP 在網(wǎng)絡(luò)深度優(yōu)化的實(shí)踐
……
6.手機(jī)淘寶雙十一性能優(yōu)化項(xiàng)目揭秘
一秒法則的實(shí)現(xiàn)
啟動(dòng)時(shí)間和頁面幀率提升 20%
Android 手機(jī)內(nèi)存節(jié)省50%
……
7.高德 APP 全鏈路源碼依賴分析
高德 APP 平臺(tái)架構(gòu)
基礎(chǔ)實(shí)現(xiàn)原理
項(xiàng)目架構(gòu)
應(yīng)用場(chǎng)景及實(shí)現(xiàn)原理
……
8.徹底干掉OOM的實(shí)戰(zhàn)經(jīng)驗(yàn)分享
排查內(nèi)存泄漏
兜底策略
內(nèi)存峰值太高
特大圖排查優(yōu)化
……
9.微信 Android終端內(nèi)存優(yōu)化實(shí)踐
Activity 泄露檢測(cè)
Bitmap 分配及回收追蹤
Native 內(nèi)存泄漏檢測(cè)
線程監(jiān)控
內(nèi)存監(jiān)控
……
總結(jié)
性能優(yōu)化不是更新一兩個(gè)版本就可以解決的,是持續(xù)性的需求,持續(xù)集成迭代反饋。在實(shí)際的項(xiàng)目中,在項(xiàng)目剛開始的時(shí)候,由于人力和項(xiàng)目完成時(shí)間限制,性能優(yōu)化的優(yōu)先級(jí)比較低,等進(jìn)入項(xiàng)目投入使用階段,就需要把優(yōu)先級(jí)提高,但在項(xiàng)目初期,在設(shè)計(jì)架構(gòu)方案時(shí),性能優(yōu)化的點(diǎn)也需要提早考慮進(jìn)去,這就體現(xiàn)出一個(gè)程序員的技術(shù)功底了。
掃碼即可領(lǐng)取資料
